diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /examples | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'examples')
151 files changed, 30019 insertions, 0 deletions
diff --git a/examples/LDAP/README b/examples/LDAP/README new file mode 100644 index 0000000..f6ce3a9 --- /dev/null +++ b/examples/LDAP/README @@ -0,0 +1,74 @@ +!== +!== README File for various LDAP examples +!== +!== written by Gerald Carter <jerry@samba.org> +!== + +OpenLDAP 2.x +------------ + +A sample schema file (samba.schema) has been included for use +with OpenLDAP 2.0.x. The OIDs used in this file are owned by +the Samba team and generated from its own Enterprise number +of 7165 (as issued by IANA). + +Copy the samba.schema file into your /etc/openldap/schema directory, +and add an include for it in the /etc/openldap/slapd.conf file. +Note that samba.schema relies upon the uid and uidNumber attributes +from the RFC2307 schema (i.e. nis.schema) + +If you choose to import /etc/passwd, nis, or nisplus tables +into ldap, you can use migration tools provided by PADL Software +which are located at + + http://www.padl.com/tools.html + +It is not a requirement that a user's /etc/passwd account +is stored in LDAP for the samba.schema file to work (although +the whole point of storing smbpasswd in LDAP is to have a +single location for user accounts, right?) + +The padl tools will leave you with LDIF files which you can import +into OpenLDAP. Before you can import them, you need to include +nis.schema and cosine.schema in your slapd.conf file. + +You must restart the LDAP server for these new included schema files +to become active. + +SunOne/Netscape DS +------------------ + +The schema file has not been updated for the sambaSamAccount +objectclass. + + +Novell eDirectory +----------------- + +The schema file has not been updated for the sambaSamAccount +objectclass. + +Fedora Directory Server / +RedHat Directory Server / +Netscape Directory Server +------------------------- + +An *updated* schema file has been provided, plus a very useful script from +Mike Jackson and Alyseo is available. +ol-schema-migrate.pl can be used to migrate OpenLDAP schema files to FDS +schema ldif files, it can also be used to validate the schema files to +make sure no duplicate OIDs or malformed entries are found. + +smbldap-tools/ +-------------- + +The smbldap-tools have been removed from the samba svn +tree. The latest version will continue to be included +in Samba releases. + +The smbldap-tools package can be downloaded individually from +https://gna.org/projects/smbldap-tools/ + +!== +!== end of README +!== diff --git a/examples/LDAP/get_next_oid b/examples/LDAP/get_next_oid new file mode 100755 index 0000000..bc3d6fc --- /dev/null +++ b/examples/LDAP/get_next_oid @@ -0,0 +1,15 @@ +#!/bin/bash + +nextattrib=$(cat samba.schema | grep -i attributetype.*\(.*1.3.6.1.4.1.7165. | grep -v '^#' | + awk '{print $3}' | cut -d. -f 10 | sort -n | tail -1) + +netattrib=$((netattrib + 1)) + +echo "attributetype ( 1.3.6.1.4.1.7165.2.1.$nextattrib NAME ...." + +nextoc=$(cat samba.schema | grep -i objectclass.*\(.*1.3.6.1.4.1.7165. | grep -v '^#' | + awk '{print $3}' | cut -d. -f 10 | sort -n | tail -1) + +nextoc=$((nextoc + 1)) + +echo "objectclass ( 1.3.6.1.4.1.7165.2.2.$nextoc NAME ...." diff --git a/examples/LDAP/ol-schema-migrate.pl b/examples/LDAP/ol-schema-migrate.pl new file mode 100755 index 0000000..c0a6f01 --- /dev/null +++ b/examples/LDAP/ol-schema-migrate.pl @@ -0,0 +1,384 @@ +#!/usr/bin/perl -w +# +# Convert OpenLDAP schema files into Fedora DS format with RFC2252 compliant printing +# +# First Release : Mike Jackson <mj@sci.fi> 14 June 2005 +# http://www.netauth.com/~jacksonm/ldap/ol-schema-migrate.pl +# Professional LDAP consulting for large and small projects +# +# - 6 Dec 2005 +# - objectclass element ordering +# +# Second Release : Alyseo <info@alyseo.com> 05 Februrary 2006 +# Francois Billard <francois@alyseo.com> +# Yacine Kheddache <yacine@alyseo.com> +# http://www.alyseo.com/ +# +# - 05 Februrary 2006 +# - parsing improvement to accept non-RFC compliant schemas (like ISPMAN) +# - adding RFC element : Usage, No-user-modification, collective keywords +# - 08 Februrary 2006 +# - adding help & usage +# - now this script can also beautify your schemas: "-b" +# - count attributes and objects class: "-c" +# - display items that can not be converted (empty OID...): "-d" +# - 15 February 2006 +# - adding workaround for Fedora DS bug 181465: +# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=181465 +# - adding duplicated OID check: "-d" +# Useful to manually correct nasty schemas like: +# https://sourceforge.net/tracker/?func=detail&atid=108390&aid=1429276&group_id=8390 +# - 13 September 2007 +# Based on Samba Team GPL Compliance Officer request, license has been updated from +# GPL to GPLv3+ +# +# - Fedora DS bug you need to correct by hand : +# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=179956 +# +# GPLv3+ license +# + +my $optionCount = 0; +my $optionPrint = 0; +my $optionBadEntries = 0; +my $optionHelp = 0; +my $filename = "" ; + +foreach (@ARGV) { + $optionHelp = 1 if ( /^-h$/); + $optionCount = 1 if ( /^-c$/); + $optionPrint = 1 if ( /^-b$/); + $optionBadEntries = 1 if ( /^-d$/); + $filename = $_ if ( ! /^-b$/ && ! /^-c$/ && ! /^-d$/); +} + +die "Usage : ol-schema-migrate-v2.pl [ -c ] [ -b ] [ -d ] schema\n" . + " -c\tcount attribute and object class\n" . + " -b\tconvert and beautify your schema\n" . + " -d\tdisplay unrecognized elements, find empty and duplicated OID\n" . + " -h\tthis help\n" if ($filename eq "" || ($optionHelp || (!$optionCount && !$optionPrint && !$optionBadEntries))); + +if($optionCount) { + print "Schema verification counters:\n"; + my $ldapdata = &getSourceFile($filename); + print "".(defined($ldapdata->{attributes}) ? @{$ldapdata->{attributes}} : 0) . " attributes\n"; + print "".(defined($ldapdata->{objectclass}) ? @{$ldapdata->{objectclass}} : 0) . " object classes\n\n" +} + +if($optionPrint) { + my $ldapdata = &getSourceFile($filename); + &printit($ldapdata); +} + +if($optionBadEntries) { + print "Display unrecognized entries:\n"; + my $ldapdata = &getSourceFile($filename); + my $errorsAttr = 0; + my $errorsObjc = 0; + my $errorsDup = 0; + my $emptyOid = 0; + my %dup; + + foreach (@{$ldapdata->{attributes}}) { + my $attr = $_; + + push @{$dup{$attr->{OID}}{attr}}, {NAME => $attr->{NAME}, LINENUMBER => $attr->{LINENUMBER}}; + + $attr->{DATA} =~ s/\n/ /g; + $attr->{DATA} =~ s/\r//g; + $attr->{DATA} =~ s/attribute[t|T]ypes?:?\s*\(//; + $attr->{DATA} =~ s/\Q$attr->{OID}// if(defined $attr->{OID}); + $attr->{DATA} =~ s/NAME\s*\Q$attr->{NAME}// if(defined $attr->{NAME}); + $attr->{DATA} =~ s/DESC\s*'\Q$attr->{DESC}'// if(defined $attr->{DESC}); + $attr->{DATA} =~ s/$attr->{OBSOLETE}// if(defined $attr->{OBSOLETE}); + $attr->{DATA} =~ s/SUP\s*\Q$attr->{SUP}// if(defined $attr->{SUP}); + $attr->{DATA} =~ s/EQUALITY\s*\Q$attr->{EQUALITY}// if(defined $attr->{EQUALITY}); + $attr->{DATA} =~ s/ORDERING\s*\Q$attr->{ORDERING}// if(defined $attr->{ORDERING}); + $attr->{DATA} =~ s/SUBSTR\s*\Q$attr->{SUBSTR}// if(defined $attr->{SUBSTR}); + $attr->{DATA} =~ s/SYNTAX\s*\Q$attr->{SYNTAX}// if(defined $attr->{SYNTAX}); + $attr->{DATA} =~ s/SINGLE-VALUE// if(defined $attr->{SINGLEVALUE}); + $attr->{DATA} =~ s/NO-USER-MODIFICATION// if(defined $attr->{NOUSERMOD}); + $attr->{DATA} =~ s/COLLECTIVE// if(defined $attr->{COLLECTIVE}); + $attr->{DATA} =~ s/USAGE\s*\Q$attr->{USAGE}// if(defined $attr->{USAGE}); + $attr->{DATA} =~ s/\)\s$//; + $attr->{DATA} =~ s/^\s+(\S)/\n$1/ ; + $attr->{DATA} =~ s/(\S)\s+$/$1\n/; + do { + $errorsAttr ++; + do { $emptyOid ++; + print "Warning : no OID for attributes element at line $attr->{LINENUMBER} \n"; + } if( !defined($attr->{OID})); + print "### Unknown element embedded in ATTRIBUTE at line $attr->{LINENUMBER} :\n$attr->{DATA}\n" + } if($attr->{DATA} =~ /\w/); + } + + foreach (@{$ldapdata->{objectclass}}) { + my $objc = $_; + push @{$dup{$objc->{OID}}{objc}} , {NAME => $objc->{NAME}, LINENUMBER => $objc->{LINENUMBER}}; + $objc->{DATA} =~ s/\n/ /g; + $objc->{DATA} =~ s/\r//g; + $objc->{DATA} =~ s/^object[c|C]lasse?s?:?\s*\(?//; + $objc->{DATA} =~ s/\Q$objc->{OID}// if(defined $objc->{OID}); + $objc->{DATA} =~ s/NAME\s*\Q$objc->{NAME}\E// if(defined $objc->{NAME}); + $objc->{DATA} =~ s/DESC\s*'\Q$objc->{DESC}\E'// if(defined $objc->{DESC}); + $objc->{DATA} =~ s/OBSOLETE// if(defined $objc->{OBSOLETE}); + $objc->{DATA} =~ s/SUP\s*\Q$objc->{SUP}// if(defined $objc->{SUP}); + $objc->{DATA} =~ s/\Q$objc->{TYPE}// if(defined $objc->{TYPE}); + $objc->{DATA} =~ s/MUST\s*\Q$objc->{MUST}\E\s*// if(defined $objc->{MUST}); + $objc->{DATA} =~ s/MUST\s*\(?\s*\Q$objc->{MUST}\E\s*\)?// if(defined $objc->{MUST}); + $objc->{DATA} =~ s/MAY\s*\Q$objc->{MAY}\E// if(defined $objc->{MAY}); + $objc->{DATA} =~ s/\)\s$//; + $objc->{DATA} =~ s/^\s+(\S)/\n$1/ ; + $objc->{DATA} =~ s/(\S)\s+$/$1\n/; + + do { + print "#" x 80 ."\n"; + $errorsObjc ++; + do { $emptyOid++ ; + print "Warning : no OID for object class element at line $objc->{LINENUMBER} \n"; + } if( $objc->{OID} eq ""); + print "### Unknown element embedded in OBJECT CLASS at line $objc->{LINENUMBER} :\n$objc->{DATA}\n" + } if($objc->{DATA} =~ /\w/); + } + + my $nbDup = 0; + foreach (keys %dup) { + my $sumOid = 0; + $sumOid += @{$dup{$_}{attr}} if(defined (@{$dup{$_}{attr}})); + $sumOid += @{$dup{$_}{objc}} if(defined (@{$dup{$_}{objc}})); + if( $sumOid > 1 && $_ ne "") { + $nbDup ++; + print "#" x 80 ."\n"; + print "Duplicate OID founds : $_\n"; + foreach (@{$dup{$_}{attr}}) { + + print "Attribute : $_->{NAME} (line : $_->{LINENUMBER})\n"; + } + foreach (@{$dup{$_}{objc}}) { + print "Object class : $_->{NAME} (line : $_->{LINENUMBER})\n"; + } + + } + } + + print "\n$errorsAttr errors detected in ATTRIBUTES list\n"; + print "$errorsObjc errors detected in OBJECT CLASS list\n"; + print "$nbDup duplicate OID founds\n"; + print "$emptyOid empty OID fields founds\n\n"; + +} + + +sub printit { + my $ldapdata = shift; + &printSeparator; + print "dn: cn=schema\n"; + &printSeparator; + + # print elements in RFC2252 order + + foreach (@{$ldapdata->{attributes}}) { + my $attr = $_; + print "attributeTypes: (\n"; + print " $attr->{OID}\n"; + print " NAME $attr->{NAME}\n"; + print " DESC '$attr->{DESC}'\n" if(defined $attr->{DESC}); + print " OBSOLETE\n" if(defined $attr->{OBSOLETE}); + print " SUP $attr->{SUP}\n" if(defined $attr->{SUP}); + print " EQUALITY $attr->{EQUALITY}\n" if(defined $attr->{EQUALITY}); + print " ORDERING $attr->{ORDERING}\n" if(defined $attr->{ORDERING}); + print " SUBSTR $attr->{SUBSTR}\n" if(defined $attr->{SUBSTR}); + print " SYNTAX $attr->{SYNTAX}\n" if(defined $attr->{SYNTAX}); + print " SINGLE-VALUE\n" if(defined $attr->{SINGLEVALUE}); + print " NO-USER-MODIFICATION\n" if(defined $attr->{NOUSERMOD}); + print " COLLECTIVE\n" if(defined $attr->{COLLECTIVE}); + print " USAGE $attr->{USAGE}\n" if(defined $attr->{USAGE}); + print " )\n"; + &printSeparator; + } + + foreach (@{$ldapdata->{objectclass}}) { + my $objc = $_; + # next 3 lines : Fedora DS space sensitive bug workaround + $objc->{SUP} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{SUP}); + $objc->{MUST} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{MUST}); + $objc->{MAY} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{MAY}); + + print "objectClasses: (\n"; + print " $objc->{OID}\n"; + print " NAME $objc->{NAME}\n"; + print " DESC '$objc->{DESC}'\n" if(defined $objc->{DESC}); + print " OBSOLETE\n" if(defined $objc->{OBSOLETE}); + print " SUP $objc->{SUP}\n" if(defined $objc->{SUP}); + print " $objc->{TYPE}\n" if(defined $objc->{TYPE}); + print " MUST $objc->{MUST}\n" if(defined $objc->{MUST}); + print " MAY $objc->{MAY}\n" if(defined $objc->{MAY}); + print " )\n"; + &printSeparator; + } +} + +sub printSeparator { + print "#\n"; + print "#" x 80 . "\n"; + print "#\n"; +} + +sub getSourceFile { + my @data = &getFile(shift); + my %result; + my $result = \%result; + my @allattrs; + my @allattrsLineNumber; + my @allobjc; + my @allobjcLineNumber; + my $at = 0; + my $oc = 0; + my $at_string; + my $oc_string; + my $idx = 0; + my $beginParenthesis = 0; + my $endParenthesis = 0; + my $lineNumber = 0; + for(@data) { + $lineNumber++; + next if (/^\s*\#/); # skip comments + + if($at) { + s/ +/ /; # remove embedded tabs + s/\t/ /; # remove multiple spaces after the $ sign + + $at_string .= $_; + $beginParenthesis = 0; # Use best matching elements + $endParenthesis = 0; + for(my $i=0;$ i < length($at_string); $i++) { + $beginParenthesis++ if(substr ($at_string,$i,1) eq "("); + $endParenthesis++ if(substr ($at_string,$i,1) eq ")"); + } + if($beginParenthesis == $endParenthesis) { + push @allattrs, $at_string; + $at = 0; + $at_string = ""; + $endParenthesis = 0; + $beginParenthesis = 0; + } + } + + if (/^attribute[t|T]ype/) { + my $line = $_; + push @allattrsLineNumber, $lineNumber; # keep starting line number + for(my $i=0;$ i < length($line); $i++) { + $beginParenthesis++ if(substr ($line, $i, 1) eq "("); + $endParenthesis++ if(substr ($line, $i, 1) eq ")"); + } + if($beginParenthesis == $endParenthesis && $beginParenthesis != 0) { + push @allattrs, $line; + $endParenthesis = 0; + $beginParenthesis = 0; + } else { + $at_string = $line; + $at = 1; + } + } + + ##################################### + + if($oc) { + s/ +/ /; + s/\t/ /; + + $oc_string .= $_; + $endParenthesis = 0; # best method to accept an elements : + $beginParenthesis = 0; # left parenthesis sum == right parenthesis sum, so we are sure to + for(my $i=0;$ i < length($oc_string); $i++) { # have an element. + $beginParenthesis++ if(substr ($oc_string, $i, 1) eq "("); + $endParenthesis++ if(substr ($oc_string, $i, 1) eq ")"); + } + if($beginParenthesis == $endParenthesis) { + push @allobjc, $oc_string; + $oc = 0; + $oc_string = ""; + $endParenthesis = 0; + $beginParenthesis = 0; + } + } + + if (/^object[c|C]lass/) { + my $line = $_; + push @allobjcLineNumber, $lineNumber; # keep starting line number + for(my $i=0;$ i < length($line); $i++) { + $beginParenthesis++ if(substr ($line, $i, 1) eq "("); + $endParenthesis++ if(substr ($line, $i, 1) eq ")"); + } + if($beginParenthesis == $endParenthesis && $beginParenthesis != 0) { + push @allobjc, $line; + $endParenthesis = 0; + $beginParenthesis = 0; + } else { + $oc_string = $line; + $oc = 1; + } + } + } + + # Parsing attribute elements + + for(@allattrs) { + s/\n/ /g; + s/\r//g; + s/ +/ /g; + s/\t/ /g; + $result->{attributes}->[$idx]->{DATA} = $_ if($optionBadEntries); # keep original data + $result->{attributes}->[$idx]->{LINENUMBER} = $allattrsLineNumber[$idx]; + $result->{attributes}->[$idx]->{OID} = $1 if (m/^attribute[t|T]ypes?:?\s*\(?\s*([\.\d]*?)\s+/); + $result->{attributes}->[$idx]->{NAME} = $1 if (m/NAME\s+('.*?')\s*/ || m/NAME\s+(\(.*?\))/); + $result->{attributes}->[$idx]->{DESC} = $1 if (m/DESC\s+'(.*?)'\s*/); + $result->{attributes}->[$idx]->{OBSOLETE} = "OBSOLETE" if (m/OBSOLETE/); + $result->{attributes}->[$idx]->{SUP} = $1 if (m/SUP\s+(.*?)\s/); + $result->{attributes}->[$idx]->{EQUALITY} = $1 if (m/EQUALITY\s+(.*?)\s/); + $result->{attributes}->[$idx]->{ORDERING} = $1 if (m/ORDERING\s+(.*?)\s/); + $result->{attributes}->[$idx]->{SUBSTR} = $1 if (m/SUBSTR\s+(.*?)\s/); + $result->{attributes}->[$idx]->{SYNTAX} = $1 if (m/SYNTAX\s+(.*?)(\s|\))/); + $result->{attributes}->[$idx]->{SINGLEVALUE} = "SINGLE-VALUE" if (m/SINGLE-VALUE/); + $result->{attributes}->[$idx]->{COLLECTIVE} = "COLLECTIVE" if (m/COLLECTIVE/); + $result->{attributes}->[$idx]->{USAGE} = $1 if (m/USAGE\s+(.*?)\s/); + $result->{attributes}->[$idx]->{NOUSERMOD} = "NO-USER-MODIFICATION" if (m/NO-USER-MODIFICATION/); + $idx ++; + } + + $idx = 0; + + # Parsing object class elements + + for(@allobjc) { + s/\n/ /g; + s/\r//g; + s/ +/ /g; + s/\t/ /g; + $result->{objectclass}->[$idx]->{DATA} = $_ if($optionBadEntries); # keep original data + $result->{objectclass}->[$idx]->{LINENUMBER} = $allobjcLineNumber[$idx]; + $result->{objectclass}->[$idx]->{OID} = $1 if (m/^object[c|C]lasse?s?:?\s*\(?\s*([\.\d]*?)\s+/); + $result->{objectclass}->[$idx]->{NAME} = $1 if (m/NAME\s+('.*?')\s*/ || m/NAME\s+(\(.*?\))/); + $result->{objectclass}->[$idx]->{DESC} = $1 if (m/DESC\s+'(.*?)'\s*/); + $result->{objectclass}->[$idx]->{OBSOLETE} = "OBSOLETE" if (m/OBSOLETE/); + $result->{objectclass}->[$idx]->{SUP} = $1 if (m/SUP\s+([^()]+?)\s/ || m/SUP\s+(\(.+?\))\s/); + $result->{objectclass}->[$idx]->{TYPE} = $1 if (m/((?:STRUCTURAL)|(?:AUXILIARY)|(?:ABSTRACT))/); + $result->{objectclass}->[$idx]->{MUST} = $1 if (m/MUST\s+(\w+)\)?/ || m/MUST\s+(\(.*?\))(\s|\))/s); + $result->{objectclass}->[$idx]->{MAY} = $1 if (m/MAY\s+(\w+)\)?/ || m/MAY\s+(\(.*?\))(\s|\))/s); + + $idx++; + } + + return $result; +} + +sub getFile { + my @data; + my $file = shift; + die "File not found : $file\n" if(! -e $file); + open FH, $file; + @data = <FH>; + close FH; + @data; +} + diff --git a/examples/LDAP/samba-nds.schema b/examples/LDAP/samba-nds.schema new file mode 100644 index 0000000..8b427b5 --- /dev/null +++ b/examples/LDAP/samba-nds.schema @@ -0,0 +1,440 @@ +## +## Schema file for Novell eDirectory by Uli Iske +## Schema for storing Samba user accounts and group maps in LDAP +## OIDs are owned by the Samba Team +## +## Prerequisite schemas rfc2307-usergroup.ldif +## +## 1.3.6.1.4.1.7165.2.1.x - attributetypes +## 1.3.6.1.4.1.7165.2.2.x - objectclasses +## +## OIDs are owned by the Samba Team +## +####################################################################### +## Attributes used by Samba 3.0 schema ## +####################################################################### + +## +## Password hashes +## + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'MD4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) + +## +## Account flags in string format ((UWDX ]) +## + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE ) + +## +## Password timestamps & policies +## + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC 'Timestamp of when the user is allowed to update the password' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC 'Timestamp of when the user will be logged off automatically' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC 'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + +## +## String settings +## + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' DESC 'List of user workstations the user is allowed to logon to' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC 'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC 'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' DESC 'Concatenated MD5 hashes of the salted NT passwords used on this account' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{1024} ) + +## +## SID, of any type +## + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +## +## Primary group SID, compatible with ntSid +## + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Security ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) + +## +## group mapping attributes +## + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +## +## Store info on domain +## + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Next NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase' DESC 'Base at which the samba RID generation algorithm should operate' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC 'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC 'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + +## +## unused +## +## dn: cn=schema +## changetype: modify +## add: attributetypes +## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.50 NAME 'sambaPrivName' SUP name ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPrivilegeList' DESC 'Privileges List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC 'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword' DESC 'Clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextPassword' DESC 'Previous clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +####################################################################### +## objectClasses used by Samba 3.0 schema ## +####################################################################### + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' DESC 'Samba 3.0 Auxilary SAM Account' SUP top AUXILIARY MUST ( uid $ sambaSID ) MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours)) + +## +## Group mapping info +## + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' DESC 'Samba Group Mapping' SUP top AUXILIARY MUST ( gidNumber $ sambaSID $ sambaGroupType ) MAY ( displayName $ description $ sambaSIDList)) + +## +## Trust password for trust relationships (any kind) +## + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' DESC 'Samba Trust Password' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet )) + +## +## Trust password for trusted domains +## (to be stored beneath the trusting sambaDomain object in the DIT) +## + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassword' SUP top STRUCTURAL DESC 'Samba Trusted Domain Password' MUST ( sambaDomainName $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY ( sambaPreviousClearTextPassword )) + +## +## Whole-of-domain info +## + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' DESC 'Samba Domain Information' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange )) + +## +## used for idmap_ldap module +## + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.1.2.2.7 NAME 'sambaUnixIdPool' DESC 'Pool for allocating UNIX uids/gids' SUP top AUXILIARY MUST ( uidNumber $ gidNumber )) + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.1.2.2.8 NAME 'sambaIdmapEntry' DESC 'Mapping from a SID to an ID' SUP top AUXILIARY MUST ( sambaSID ) MAY ( uidNumber $ gidNumber )) + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.1.2.2.9 NAME 'sambaSidEntry' DESC 'Structural Class for a SID' SUP top STRUCTURAL MUST ( sambaSID )) + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.1.2.2.10 NAME 'sambaConfig' DESC 'Samba Configuration Section' SUP top AUXILIARY MAY ( description )) + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' DESC 'Samba Share Section' SUP top STRUCTURAL MUST ( sambaShareName ) MAY ( description )) + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' DESC 'Samba Configuration Option' SUP top STRUCTURAL MUST ( sambaOptionName ) MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoption $ description )) + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.13 NAME 'sambaPrivilege' DESC 'Samba Privilege' SUP top AUXILIARY MUST ( sambaSID ) MAY ( sambaPrivilegeList )) + +dn: cn=schema +changetype: modify +add: objectClasses +objectClasses: ( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL DESC 'Samba Trusted Domain Object' MUST ( cn ) MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncryptionTypes ) ) diff --git a/examples/LDAP/samba-schema-FDS.ldif b/examples/LDAP/samba-schema-FDS.ldif new file mode 100644 index 0000000..fdfdab6 --- /dev/null +++ b/examples/LDAP/samba-schema-FDS.ldif @@ -0,0 +1,190 @@ +## schema file for Fedora/RedHat Directory Server +## +## NOTE: this file can be copied as 60samba.ldif into your instance schema +## directory: +## cp samba-schema-FDS.ldif /etc/dirsrv/slapd-<instance-name>/schema/60schema.ldif +## +## Schema for storing Samba user accounts and group maps in LDAP +## OIDs are owned by the Samba Team +## +## Prerequisite schemas - uid (cosine.schema) +## - displayName (inetorgperson.schema) +## - gidNumber (nis.schema) +## +## 1.3.6.1.4.1.7165.2.1.x - attributeTypess +## 1.3.6.1.4.1.7165.2.2.x - objectClasseses +## +## Printer support +## 1.3.6.1.4.1.7165.2.3.1.x - attributeTypess +## 1.3.6.1.4.1.7165.2.3.2.x - objectClasseses +## +## Samba4 +## 1.3.6.1.4.1.7165.4.1.x - attributeTypess +## 1.3.6.1.4.1.7165.4.2.x - objectClasseses +## 1.3.6.1.4.1.7165.4.3.x - LDB/LDAP Controls +## 1.3.6.1.4.1.7165.4.4.x - LDB/LDAP Extended Operations +## 1.3.6.1.4.1.7165.4.255.x - mapped OIDs due to conflicts between AD and standards-track +## +dn: cn=schema +## +####################################################################### +## Attributes used by Samba 3.0 schema ## +####################################################################### +## +## Password hashes## +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'MD4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +## +## Account flags in string format ([UWDX ]) +## +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE ) +## +## Password timestamps & policies +## +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC 'Timestamp of when the user is allowed to update the password' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC 'Timestamp of when the user will be logged off automatically' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC 'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{42} SINGLE-VALUE ) +## +## string settings +## +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' DESC 'List of user workstations the user is allowed to logon to' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC 'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC 'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' DESC 'Concatenated MD5 hashes of the salted NT passwords used on this account' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} ) +## +## SID, of any type +## +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) +## +## Primary group SID, compatible with ntSid +## +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Security ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) +## +## group mapping attributes +## +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +## +## Store info on the domain +## +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Next NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase' DESC 'Base at which the samba RID generation algorithm should operate' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC 'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC 'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +##attributeTypes: ( 1.3.6.1.4.1.7165.2.1.50 NAME 'sambaPrivName' +## SUP name ) +## +##attributeTypes: ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPrivilegeList' +## DESC 'Privileges List' +## EQUALITY caseIgnoreIA5Match +## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC 'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +# "min password length" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "password history" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "user must logon to change password" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "maximum password age" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "minimum password age" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "lockout duration" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "reset count minutes" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "bad lockout attempt" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "disconnect time" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# "refuse machine password change" +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword' DESC 'Clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextPassword' DESC 'Previous clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +# +attributeTypes: ( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +## +####################################################################### +## objectClasses: used by Samba 3.0 schema ## +####################################################################### +## +## The X.500 data model (and therefore LDAPv3) says that each entry can +## only have one structural objectClasses. OpenLDAP 2.0 does not enforce +## this currently but will in v2.1 +## +## added new objectClasses: (and OID) for 3.0 to help us deal with backwards +## compatibility with 2.2 installations (e.g. ldapsam_compat) --jerry +## +objectClasses: ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY DESC 'Samba 3.0 Auxilary SAM Account' MUST ( uid $ sambaSID ) MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours)) +## +## Group mapping info +## +objectClasses: ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY DESC 'Samba Group Mapping' MUST ( gidNumber $ sambaSID $ sambaGroupType ) MAY ( displayName $ description $ sambaSIDList )) +## +## Trust password for trust relationships (any kind) +## +objectClasses: ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' SUP top STRUCTURAL DESC 'Samba Trust Password' MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet )) +## +## Whole-of-domain info +## +objectClasses: ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL DESC 'Samba Domain Information' MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange )) +## +## used for idmap_ldap module +## +objectClasses: ( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY DESC 'Pool for allocating UNIX uids/gids' MUST ( uidNumber $ gidNumber ) ) +objectClasses: ( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY DESC 'Mapping from a SID to an ID' MUST ( sambaSID ) MAY ( uidNumber $ gidNumber ) ) +objectClasses: ( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL DESC 'Structural Class for a SID' MUST ( sambaSID ) ) +objectClasses: ( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' SUP top AUXILIARY DESC 'Samba Configuration Section' MAY ( description ) ) +objectClasses: ( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' SUP top STRUCTURAL DESC 'Samba Share Section' MUST ( sambaShareName ) MAY ( description ) ) +objectClasses: ( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' SUP top STRUCTURAL DESC 'Samba Configuration Option' MUST ( sambaOptionName ) MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoption $ description ) ) +## retired during privilege rewrite +##objectClasses: ( 1.3.6.1.4.1.7165.2.2.13 NAME 'sambaPrivilege' SUP top AUXILIARY +## DESC 'Samba Privilege' +## MUST ( sambaSID ) +## MAY ( sambaPrivilegeList ) ) +## +## Trusted Domain Relationships +## +objectClasses: ( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassword' SUP top STRUCTURAL DESC 'Samba Trusted Domain Password' MUST ( sambaDomainName $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY ( sambaPreviousClearTextPassword ) ) +## +## used for IPA_ldapsam +## +objectClasses: ( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL DESC 'Samba Trusted Domain Object' MUST ( cn ) MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncryptionTypes) ) diff --git a/examples/LDAP/samba-schema-netscapeds5.x.README b/examples/LDAP/samba-schema-netscapeds5.x.README new file mode 100644 index 0000000..78c9073 --- /dev/null +++ b/examples/LDAP/samba-schema-netscapeds5.x.README @@ -0,0 +1,2 @@ +The LDAP schema file for the Netscape DS 5 has been outdated since years. +Please use the LDIF based FDS schema file instead. diff --git a/examples/LDAP/samba-schema.IBMSecureWay b/examples/LDAP/samba-schema.IBMSecureWay new file mode 100644 index 0000000..c45a334 --- /dev/null +++ b/examples/LDAP/samba-schema.IBMSecureWay @@ -0,0 +1,43 @@ +## +## Submitted by Dirk Kastens <Dirk.Kastens@Uni-Osnabrueck.de> +## +## I translated the samba.schema to be used with IBM +## SecureWay directory server 3.2.2. You have to load +## it in your slapd32.conf with: +## +## dn: cn=IBM SecureWay, cn=Schemas, cn=Configuration +## cn: IBM SecureWay +## ibm-slapdIncludeSchema: /etc/lapschema/samba.schema +## +objectClasses { +( 1.3.1.5.1.4.1.7165.2.2.2 NAME 'sambaAccount' DESC 'Samba Account' SUP top MUST uid $ rid MAY ( acctFlags $ cn $ description $ displayName $ homeDrive $ kickoffTime $ lmPassword $ logoffTime $ logonTime $ ntPassword $ primaryGroupID $ profilePath $ pwdCanChange $ pwdLastSet $ pwdMustChange $ scriptPath $ smbHome $ userWorkstations ) ) +} + +attributeTypes { +( 1.3.6.1.4.1.7165.2.1.1 NAME 'lmPassword' DESC 'LanManager Passwd' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.10 NAME 'homeDrive' DESC 'NT homeDrive' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.11 NAME 'scriptPath' DESC 'NT scriptPath' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.12 NAME 'profilePath' DESC 'NT profilePath' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.13 NAME 'userWorkstations' DESC 'userWorkstations' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.14 NAME 'rid' DESC 'NT rid' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.15 NAME 'primaryGroupID' DESC 'NT Group RID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.17 NAME 'smbHome' DESC 'smbHome' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} ) +( 1.3.6.1.4.1.7165.2.1.2 NAME 'ntPassword' DESC 'NT Passwd' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.3 NAME 'pwdLastSet' DESC 'NT pwdLastSet' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.4 NAME 'acctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.5 NAME 'logonTime' DESC 'NT logonTime' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.6 NAME 'logoffTime' DESC 'NT logoffTime' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.7 NAME 'kickoffTime' DESC 'NT kickoffTime' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.8 NAME 'pwdCanChange' DESC 'NT pwdCanChange' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +( 1.3.6.1.4.1.7165.2.1.9 NAME 'pwdMustChange' DESC 'NT pwdMustChange' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +} + +IBMattributeTypes { +} + +ldapSyntaxes { +} + +matchingRules { +} + diff --git a/examples/LDAP/samba.ldif b/examples/LDAP/samba.ldif new file mode 100644 index 0000000..5106e5f --- /dev/null +++ b/examples/LDAP/samba.ldif @@ -0,0 +1,224 @@ +dn: cn=samba,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: samba +olcAttributeTypes: {0}( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'L + anManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.1 + 21.1.26{32} SINGLE-VALUE ) +olcAttributeTypes: {1}( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'M + D4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4 + .1.1466.115.121.1.26{32} SINGLE-VALUE ) +olcAttributeTypes: {2}( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Ac + count Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + {16} SINGLE-VALUE ) +olcAttributeTypes: {3}( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'T + imestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4. + 1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {4}( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC + 'Timestamp of when the user is allowed to update the password' EQUALITY integ + erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {5}( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC + 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1. + 3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {6}( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Ti + mestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121. + 1.27 SINGLE-VALUE ) +olcAttributeTypes: {7}( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'T + imestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.12 + 1.1.27 SINGLE-VALUE ) +olcAttributeTypes: {8}( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC ' + Timestamp of when the user will be logged off automatically' EQUALITY integer + Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {9}( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' D + ESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.146 + 6.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {10}( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' D + ESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3. + 6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {11}( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC ' + Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + {42} SINGLE-VALUE ) +olcAttributeTypes: {12}( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'D + river letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1. + 3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE ) +olcAttributeTypes: {13}( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC + 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121. + 1.15{255} SINGLE-VALUE ) +olcAttributeTypes: {14}( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC + 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.1 + 21.1.15{255} SINGLE-VALUE ) +olcAttributeTypes: {15}( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' + DESC 'List of user workstations the user is allowed to logon to' EQUALITY cas + eIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) +olcAttributeTypes: {16}( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Ho + me directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.1 + 21.1.15{128} ) +olcAttributeTypes: {17}( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC ' + Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX + 1.3.6.1.4.1.1466.115.121.1.15{128} ) +olcAttributeTypes: {18}( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC ' + Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1. + 4.1.1466.115.121.1.15{1050} ) +olcAttributeTypes: {19}( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' D + ESC 'Concatenated MD5 hashes of the salted NT passwords used on this account' + EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} ) +olcAttributeTypes: {20}( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Securit + y ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1 + .3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) +olcAttributeTypes: {21}( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' D + ESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4. + 1.1466.115.121.1.26{64} SINGLE-VALUE ) +olcAttributeTypes: {22}( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Sec + urity ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1. + 26{64} ) +olcAttributeTypes: {23}( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'N + T Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SING + LE-VALUE ) +olcAttributeTypes: {24}( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC + 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1. + 1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {25}( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC + 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4. + 1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {26}( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Nex + t NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1 + 466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {27}( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase + ' DESC 'Base at which the samba RID generation algorithm should operate' EQUA + LITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {28}( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'S + hare Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SING + LE-VALUE ) +olcAttributeTypes: {29}( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC ' + Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX + 1.3.6.1.4.1.1466.115.121.1.15{256} ) +olcAttributeTypes: {30}( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC ' + A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 S + INGLE-VALUE ) +olcAttributeTypes: {31}( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DES + C 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1 + .27 SINGLE-VALUE ) +olcAttributeTypes: {32}( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC + 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121 + .1.26 SINGLE-VALUE ) +olcAttributeTypes: {33}( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' + DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466. + 115.121.1.15 ) +olcAttributeTypes: {34}( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC ' + Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115 + .121.1.26 ) +olcAttributeTypes: {35}( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC + 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1. + 4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {36}( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' + DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY intege + rMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {37}( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DES + C 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQU + ALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {38}( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'M + aximum password age, in seconds (default: -1 => never expire passwords)' EQUA + LITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {39}( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'M + inimum password age, in seconds (default: 0 => allow immediate password chang + e)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {40}( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' D + ESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integ + erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {41}( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservation + Window' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY int + egerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {42}( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' + DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY in + tegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {43}( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC + 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY + integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {44}( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdCh + ange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY inte + gerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {45}( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword' + DESC 'Clear text password (used for trusted domain passwords)' EQUALITY octe + tStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +olcAttributeTypes: {46}( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextP + assword' DESC 'Previous clear text password (used for trusted domain password + s)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +olcAttributeTypes: {47}( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'T + ype of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SING + LE-VALUE ) +olcAttributeTypes: {48}( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' D + ESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3. + 6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {49}( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DE + SC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.1 + 21.1.27 SINGLE-VALUE ) +olcAttributeTypes: {50}( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC + 'Fully qualified name of the domain with which a trust exists' EQUALITY case + IgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) +olcAttributeTypes: {51}( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'Ne + tBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115. + 121.1.15{128} ) +olcAttributeTypes: {52}( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' + DESC 'Authentication information for the outgoing portion of a trust' EQUALIT + Y caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) +olcAttributeTypes: {53}( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' + DESC 'Authentication information for the incoming portion of a trust' EQUALIT + Y caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) +olcAttributeTypes: {54}( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier + ' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExact + IA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) +olcAttributeTypes: {55}( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustIn + fo' DESC 'Forest trust information for a trusted domain object' EQUALITY case + ExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) +olcAttributeTypes: {56}( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' + DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466. + 115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {57}( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptio + nTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SY + NTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcObjectClasses: {0}( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' DESC 'Sam + ba 3.0 Auxilary SAM Account' SUP top AUXILIARY MUST ( uid $ sambaSID ) MAY ( + cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ s + ambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $ + sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScr + ipt $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGr + oupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBad + PasswordTime $ sambaPasswordHistory $ sambaLogonHours ) ) +olcObjectClasses: {1}( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' DESC 'S + amba Group Mapping' SUP top AUXILIARY MUST ( gidNumber $ sambaSID $ sambaGrou + pType ) MAY ( displayName $ description $ sambaSIDList ) ) +olcObjectClasses: {2}( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' DESC + 'Samba Trust Password' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaNTPas + sword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet ) ) +olcObjectClasses: {3}( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPasswor + d' DESC 'Samba Trusted Domain Password' SUP top STRUCTURAL MUST ( sambaDomain + Name $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY sambaPreviou + sClearTextPassword ) +olcObjectClasses: {4}( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' DESC 'Samba D + omain Information' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaSID ) MAY + ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidB + ase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaM + axPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWin + dow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange + ) ) +olcObjectClasses: {5}( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' DESC 'Poo + l for allocating UNIX uids/gids' SUP top AUXILIARY MUST ( uidNumber $ gidNumb + er ) ) +olcObjectClasses: {6}( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' DESC 'Map + ping from a SID to an ID' SUP top AUXILIARY MUST sambaSID MAY ( uidNumber $ g + idNumber ) ) +olcObjectClasses: {7}( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' DESC 'Struc + tural Class for a SID' SUP top STRUCTURAL MUST sambaSID ) +olcObjectClasses: {8}( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' DESC 'Samba + Configuration Section' SUP top AUXILIARY MAY description ) +olcObjectClasses: {9}( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' DESC 'Samba S + hare Section' SUP top STRUCTURAL MUST sambaShareName MAY description ) +olcObjectClasses: {10}( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' DESC + 'Samba Configuration Option' SUP top STRUCTURAL MUST sambaOptionName MAY ( sa + mbaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoptio + n $ description ) ) +olcObjectClasses: {11}( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' DESC + 'Samba Trusted Domain Object' SUP top STRUCTURAL MUST cn MAY ( sambaTrustTyp + e $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFla + tName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdenti + fier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncr + yptionTypes) ) diff --git a/examples/LDAP/samba.schema b/examples/LDAP/samba.schema new file mode 100644 index 0000000..58d7a82 --- /dev/null +++ b/examples/LDAP/samba.schema @@ -0,0 +1,649 @@ +## +## schema file for OpenLDAP 2.x +## Schema for storing Samba user accounts and group maps in LDAP +## OIDs are owned by the Samba Team +## +## Prerequisite schemas - uid (cosine.schema) +## - displayName (inetorgperson.schema) +## - gidNumber (nis.schema) +## +## 1.3.6.1.4.1.7165.2.1.x - attributetypes +## 1.3.6.1.4.1.7165.2.2.x - objectclasses +## +## Printer support +## 1.3.6.1.4.1.7165.2.3.1.x - attributetypes +## 1.3.6.1.4.1.7165.2.3.2.x - objectclasses +## +## Samba4 - see source4/setup/schema_samba4.ldif +## 1.3.6.1.4.1.7165.4.1.x - attributetypes +## 1.3.6.1.4.1.7165.4.2.x - objectclasses +## 1.3.6.1.4.1.7165.4.3.x - LDB/LDAP Controls +## 1.3.6.1.4.1.7165.4.4.x - LDB/LDAP Extended Operations +## 1.3.6.1.4.1.7165.4.5.x - ldap extended matches +## 1.3.6.1.4.1.7165.4.6.1.x - SELFTEST random attributes +## 1.3.6.1.4.1.7165.4.255.x - mapped OIDs due to conflicts between AD and standards-track +## +## Out of tree use allocated in the wiki +## 1.3.6.1.4.1.7165.777.x - https://wiki.samba.org/index.php/Samba_AD_schema_extensions#OID +## +## External projects +## 1.3.6.1.4.1.7165.655.x +## 1.3.6.1.4.1.7165.655.1.x - GSS-NTLMSSP +## +## ----- READ THIS WHEN ADDING A NEW ATTRIBUTE OR OBJECT CLASS ------ +## +## Run the 'get_next_oid' bash script in this directory to find the +## next available OID for attribute type and object classes. +## +## $ ./get_next_oid +## attributetype ( 1.3.6.1.4.1.7165.2.1.XX NAME .... +## objectclass ( 1.3.6.1.4.1.7165.2.2.XX NAME .... +## +## Also ensure that new entries adhere to the declaration style +## used throughout this file +## +## <attributetype|objectclass> ( 1.3.6.1.4.1.7165.2.XX.XX NAME .... +## ^ ^ ^ +## +## The spaces are required for the get_next_oid script (and for +## readability). +## +## ------------------------------------------------------------------ + +# objectIdentifier SambaRoot 1.3.6.1.4.1.7165 +# objectIdentifier Samba3 SambaRoot:2 +# objectIdentifier Samba3Attrib Samba3:1 +# objectIdentifier Samba3ObjectClass Samba3:2 +# objectIdentifier Samba4 SambaRoot:4 + +######################################################################## +## HISTORICAL ## +######################################################################## + +## +## Password hashes +## +#attributetype ( 1.3.6.1.4.1.7165.2.1.1 NAME 'lmPassword' +# DESC 'LanManager Passwd' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.2 NAME 'ntPassword' +# DESC 'NT Passwd' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) + +## +## Account flags in string format ([UWDX ]) +## +#attributetype ( 1.3.6.1.4.1.7165.2.1.4 NAME 'acctFlags' +# DESC 'Account Flags' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE ) + +## +## Password timestamps & policies +## +#attributetype ( 1.3.6.1.4.1.7165.2.1.3 NAME 'pwdLastSet' +# DESC 'NT pwdLastSet' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.5 NAME 'logonTime' +# DESC 'NT logonTime' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.6 NAME 'logoffTime' +# DESC 'NT logoffTime' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.7 NAME 'kickoffTime' +# DESC 'NT kickoffTime' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.8 NAME 'pwdCanChange' +# DESC 'NT pwdCanChange' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.9 NAME 'pwdMustChange' +# DESC 'NT pwdMustChange' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +## +## string settings +## +#attributetype ( 1.3.6.1.4.1.7165.2.1.10 NAME 'homeDrive' +# DESC 'NT homeDrive' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.11 NAME 'scriptPath' +# DESC 'NT scriptPath' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.12 NAME 'profilePath' +# DESC 'NT profilePath' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.13 NAME 'userWorkstations' +# DESC 'userWorkstations' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.17 NAME 'smbHome' +# DESC 'smbHome' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.18 NAME 'domain' +# DESC 'Windows NT domain to which the user belongs' +# EQUALITY caseIgnoreIA5Match +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} ) + +## +## user and group RID +## +#attributetype ( 1.3.6.1.4.1.7165.2.1.14 NAME 'rid' +# DESC 'NT rid' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +#attributetype ( 1.3.6.1.4.1.7165.2.1.15 NAME 'primaryGroupID' +# DESC 'NT Group RID' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +## +## The smbPasswordEntry objectclass has been depreciated in favor of the +## sambaAccount objectclass +## +#objectclass ( 1.3.6.1.4.1.7165.2.2.1 NAME 'smbPasswordEntry' SUP top AUXILIARY +# DESC 'Samba smbpasswd entry' +# MUST ( uid $ uidNumber ) +# MAY ( lmPassword $ ntPassword $ pwdLastSet $ acctFlags )) + +#objectclass ( 1.3.6.1.4.1.7165.2.2.2 NAME 'sambaAccount' SUP top STRUCTURAL +# DESC 'Samba Account' +# MUST ( uid $ rid ) +# MAY ( cn $ lmPassword $ ntPassword $ pwdLastSet $ logonTime $ +# logoffTime $ kickoffTime $ pwdCanChange $ pwdMustChange $ acctFlags $ +# displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $ +# description $ userWorkstations $ primaryGroupID $ domain )) + +#objectclass ( 1.3.6.1.4.1.7165.2.2.3 NAME 'sambaAccount' SUP top AUXILIARY +# DESC 'Samba Auxiliary Account' +# MUST ( uid $ rid ) +# MAY ( cn $ lmPassword $ ntPassword $ pwdLastSet $ logonTime $ +# logoffTime $ kickoffTime $ pwdCanChange $ pwdMustChange $ acctFlags $ +# displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $ +# description $ userWorkstations $ primaryGroupID $ domain )) + +######################################################################## +## END OF HISTORICAL ## +######################################################################## + +####################################################################### +## Attributes used by Samba 3.0 schema ## +####################################################################### + +## +## Password hashes +## +attributetype ( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' + DESC 'LanManager Password' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' + DESC 'MD4 hash of the unicode password' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) + +## +## Account flags in string format ([UWDX ]) +## +attributetype ( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' + DESC 'Account Flags' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE ) + +## +## Password timestamps & policies +## +attributetype ( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' + DESC 'Timestamp of the last password update' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' + DESC 'Timestamp of when the user is allowed to update the password' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' + DESC 'Timestamp of when the password will expire' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' + DESC 'Timestamp of last logon' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' + DESC 'Timestamp of last logoff' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' + DESC 'Timestamp of when the user will be logged off automatically' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' + DESC 'Bad password attempt count' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' + DESC 'Time of the last bad password attempt' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' + DESC 'Logon Hours' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{42} SINGLE-VALUE ) + +## +## string settings +## +attributetype ( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' + DESC 'Driver letter of home directory mapping' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' + DESC 'Logon script path' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' + DESC 'Roaming profile path' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' + DESC 'List of user workstations the user is allowed to logon to' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' + DESC 'Home directory UNC path' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' + DESC 'Windows NT domain to which the user belongs' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' + DESC 'Base64 encoded user parameter string' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' + DESC 'Concatenated MD5 hashes of the salted NT passwords used on this account' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} ) + +## +## SID, of any type +## + +attributetype ( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' + DESC 'Security ID' + EQUALITY caseIgnoreIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +## +## Primary group SID, compatible with ntSid +## + +attributetype ( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' + DESC 'Primary Group Security ID' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' + DESC 'Security ID List' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) + +## +## group mapping attributes +## +attributetype ( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' + DESC 'NT Group Type' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +## +## Store info on the domain +## + +attributetype ( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' + DESC 'Next NT rid to give our for users' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' + DESC 'Next NT rid to give out for groups' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' + DESC 'Next NT rid to give out for anything' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase' + DESC 'Base at which the samba RID generation algorithm should operate' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' + DESC 'Share Name' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' + DESC 'Option Name' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' + DESC 'A boolean option' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' + DESC 'An integer option' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' + DESC 'A string option' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' + DESC 'A string list option' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + + +##attributetype ( 1.3.6.1.4.1.7165.2.1.50 NAME 'sambaPrivName' +## SUP name ) + +##attributetype ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPrivilegeList' +## DESC 'Privileges List' +## EQUALITY caseIgnoreIA5Match +## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' + DESC 'Trust Password Flags' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +# "min password length" +attributetype ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' + DESC 'Minimal password length (default: 5)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "password history" +attributetype ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' + DESC 'Length of Password History Entries (default: 0 => off)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "user must logon to change password" +attributetype ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' + DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "maximum password age" +attributetype ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' + DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "minimum password age" +attributetype ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' + DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "lockout duration" +attributetype ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' + DESC 'Lockout duration in minutes (default: 30, -1 => forever)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "reset count minutes" +attributetype ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' + DESC 'Reset time after lockout in minutes (default: 30)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "bad lockout attempt" +attributetype ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' + DESC 'Lockout users after bad logon attempts (default: 0 => off)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "disconnect time" +attributetype ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' + DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# "refuse machine password change" +attributetype ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' + DESC 'Allow Machine Password changes (default: 0 => off)' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +# +attributetype ( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword' + DESC 'Clear text password (used for trusted domain passwords)' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) + +# +attributetype ( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextPassword' + DESC 'Previous clear text password (used for trusted domain passwords)' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' + DESC 'Type of trust' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' + DESC 'Trust attributes for a trusted domain' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' + DESC 'Direction of a trust' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' + DESC 'Fully qualified name of the domain with which a trust exists' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' + DESC 'NetBIOS name of a domain' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' + DESC 'Authentication information for the outgoing portion of a trust' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' + DESC 'Authentication information for the incoming portion of a trust' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier' + DESC 'SID of a trusted domain' + EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo' + DESC 'Forest trust information for a trusted domain object' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' + DESC 'POSIX offset of a trust' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes' + DESC 'Supported encryption types of a trust' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +####################################################################### +## objectClasses used by Samba 3.0 schema ## +####################################################################### + +## The X.500 data model (and therefore LDAPv3) says that each entry can +## only have one structural objectclass. OpenLDAP 2.0 does not enforce +## this currently but will in v2.1 + +## +## added new objectclass (and OID) for 3.0 to help us deal with backwards +## compatibility with 2.2 installations (e.g. ldapsam_compat) --jerry +## +objectclass ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY + DESC 'Samba 3.0 Auxilary SAM Account' + MUST ( uid $ sambaSID ) + MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ + sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $ + sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $ + displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $ + sambaProfilePath $ description $ sambaUserWorkstations $ + sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ + sambaBadPasswordCount $ sambaBadPasswordTime $ + sambaPasswordHistory $ sambaLogonHours)) + +## +## Group mapping info +## +objectclass ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY + DESC 'Samba Group Mapping' + MUST ( gidNumber $ sambaSID $ sambaGroupType ) + MAY ( displayName $ description $ sambaSIDList )) + +## +## Trust password for trust relationships (any kind) +## +objectclass ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' SUP top STRUCTURAL + DESC 'Samba Trust Password' + MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags ) + MAY ( sambaSID $ sambaPwdLastSet )) + +## +## Trust password for trusted domains +## (to be stored beneath the trusting sambaDomain object in the DIT) +## +objectclass ( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassword' SUP top STRUCTURAL + DESC 'Samba Trusted Domain Password' + MUST ( sambaDomainName $ sambaSID $ + sambaClearTextPassword $ sambaPwdLastSet ) + MAY ( sambaPreviousClearTextPassword )) + +## +## Whole-of-domain info +## +objectclass ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL + DESC 'Samba Domain Information' + MUST ( sambaDomainName $ + sambaSID ) + MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ + sambaAlgorithmicRidBase $ + sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ + sambaMaxPwdAge $ sambaMinPwdAge $ + sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ + sambaForceLogoff $ sambaRefuseMachinePwdChange )) + +## +## used for idmap_ldap module +## +objectclass ( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY + DESC 'Pool for allocating UNIX uids/gids' + MUST ( uidNumber $ gidNumber ) ) + + +objectclass ( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY + DESC 'Mapping from a SID to an ID' + MUST ( sambaSID ) + MAY ( uidNumber $ gidNumber ) ) + +objectclass ( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL + DESC 'Structural Class for a SID' + MUST ( sambaSID ) ) + +objectclass ( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' SUP top AUXILIARY + DESC 'Samba Configuration Section' + MAY ( description ) ) + +objectclass ( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' SUP top STRUCTURAL + DESC 'Samba Share Section' + MUST ( sambaShareName ) + MAY ( description ) ) + +objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' SUP top STRUCTURAL + DESC 'Samba Configuration Option' + MUST ( sambaOptionName ) + MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ + sambaStringListoption $ description ) ) + + +## retired during privilege rewrite +##objectclass ( 1.3.6.1.4.1.7165.2.2.13 NAME 'sambaPrivilege' SUP top AUXILIARY +## DESC 'Samba Privilege' +## MUST ( sambaSID ) +## MAY ( sambaPrivilegeList ) ) + +## +## used for IPA_ldapsam +## +objectclass ( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL + DESC 'Samba Trusted Domain Object' + MUST ( cn ) + MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $ + sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $ + sambaTrustAuthIncoming $ sambaSecurityIdentifier $ + sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ + sambaSupportedEncryptionTypes) ) diff --git a/examples/LDAP/samba.schema.at.IBM-DS b/examples/LDAP/samba.schema.at.IBM-DS new file mode 100644 index 0000000..77ddef8 --- /dev/null +++ b/examples/LDAP/samba.schema.at.IBM-DS @@ -0,0 +1,116 @@ +## Samba 3.0 schema for IBM Directory Server 5.1 - attribute Types only + +attributetypes=( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +IBMAttributetypes=( 1.3.6.1.4.1.7165.2.1.24 DBNAME( 'sambaLMPassword' 'sambaLMPassword' ) ACCESS-CLASS critical ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'MD4 hash of the unicode password'EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) +IBMAttributetypes=( 1.3.6.1.4.1.7165.2.1.25 DBNAME( 'sambaNTPassword' 'sambaNTPassword' ) ACCESS-CLASS critical ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC 'Timestamp of when the user is allowed to update the password' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC 'Timestamp of when the user will be logged off automatically' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' DESC 'List of user workstations the user is allowed to logon to' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC 'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Next NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase' DESC 'Base at which the samba RID generation algorithm should operate' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC 'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC 'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC 'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Security ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC 'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' DESC 'Concatenated MD4 hashes of the unicode passwords used on this account' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) +IBMAttributetypes=( 1.3.6.1.4.1.7165.2.1.54 DBNAME( 'sambaPasswordHistory' 'sambaPasswordHistory' ) ACCESS-CLASS critical ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC 'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{42} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetypes=( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) diff --git a/examples/LDAP/samba.schema.oc.IBM-DS b/examples/LDAP/samba.schema.oc.IBM-DS new file mode 100644 index 0000000..c3ed05b --- /dev/null +++ b/examples/LDAP/samba.schema.oc.IBM-DS @@ -0,0 +1,23 @@ +## Samba 3.0 schema for IBM Directory Server 5.1 - object classes only + +objectclasses=( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY DESC 'Samba 3.0 Auxilary SAM Account' MUST ( uid $ sambaSID ) MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours)) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY DESC 'Samba Group Mapping' MUST ( gidNumber $ sambaSID $ sambaGroupType ) MAY ( displayName $ description $ sambaSIDList )) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL DESC 'Samba Domain Information' MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange ) ) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY DESC 'Pool for allocating UNIX uids/gids' MUST ( uidNumber $ gidNumber ) ) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY DESC 'Mapping from a SID to an ID' MUST ( sambaSID ) MAY ( uidNumber $ gidNumber ) ) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL DESC 'Structural Class for a SID' MUST ( sambaSID ) ) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' SUP top AUXILIARY DESC 'Samba Configuration Section' MAY ( description ) ) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' SUP top STRUCTURAL DESC 'Samba Share Section' MUST ( sambaShareName ) MAY ( description ) ) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' SUP top STRUCTURAL DESC 'Samba Configuration Option' MUST ( sambaOptionName ) MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoption $ description ) ) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' SUP top STRUCTURAL DESC 'Samba Trust Password' MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet )) + +objectclasses=( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL DESC 'Samba Trusted Domain Object' MUST ( cn ) MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncryptionTypes ) ) diff --git a/examples/README b/examples/README new file mode 100644 index 0000000..950baf1 --- /dev/null +++ b/examples/README @@ -0,0 +1,11 @@ +Copyright(C) Samba-Team 1993-2001 + +This directory contains example config files and related material for +Samba. + +At a minimum please refer to the smb.conf.default file for current +information regarding global and share parameter settings. + +To contribute to Samba see: https://wiki.samba.org/index.php/Contribute + + diff --git a/examples/VFS/README b/examples/VFS/README new file mode 100644 index 0000000..dc99e20 --- /dev/null +++ b/examples/VFS/README @@ -0,0 +1,20 @@ +README for Samba Virtual File System (VFS) Example +=================================================== + +This directory contains skeleton VFS modules. When used, +this module simply passes all requests back to the disk functions +(i.e it operates as a passthrough filter). It should be +useful as a starting point for developing new VFS +modules. + +Please look at skel_opaque.c when you want your module to provide +final functions, like a database filesystem. + +Please look at skel_transparent.c when you want your module to provide +passthrough functions, like audit modules. + +Please read the VFS chapter in the HOWTO collection for general help +on the usage of VFS modules. + +Further documentation on writing VFS modules for Samba can be found in +Samba Developers Guide. diff --git a/examples/VFS/shadow_copy_test.c b/examples/VFS/shadow_copy_test.c new file mode 100644 index 0000000..157e576 --- /dev/null +++ b/examples/VFS/shadow_copy_test.c @@ -0,0 +1,92 @@ +/* + * TEST implementation of an Shadow Copy module + * + * Copyright (C) Stefan Metzmacher 2003 + * Copyright (C) Jeremy Allison 2009. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "../source3/include/includes.h" +#include "ntioctl.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +/* USE THIS MODULE ONLY FOR TESTING!!!! */ + +/* + For this share + Z:\ + + the ShadowCopies are in these directories + + Z:\@GMT-2003.08.05-12.00.00\ + Z:\@GMT-2003.08.05-12.01.00\ + Z:\@GMT-2003.08.05-12.02.00\ + + e.g. + + Z:\testfile.txt + Z:\@GMT-2003.08.05-12.02.00\testfile.txt + + or: + + Z:\testdir\testfile.txt + Z:\@GMT-2003.08.05-12.02.00\testdir\testfile.txt + + + Note: Files must differ to be displayed via Windows Explorer! + Directories are always displayed... +*/ + +static int test_get_shadow_copy_data(vfs_handle_struct *handle, + files_struct *fsp, + struct shadow_copy_data *shadow_copy_data, + bool labels) +{ + uint32_t num = 3; + uint32_t i; + + shadow_copy_data->num_volumes = num; + + if (labels) { + if (num) { + shadow_copy_data->labels = talloc_zero_array(shadow_copy_data,SHADOW_COPY_LABEL,num); + } else { + shadow_copy_data->labels = NULL; + } + for (i=0;i<num;i++) { + snprintf(shadow_copy_data->labels[i], sizeof(SHADOW_COPY_LABEL), "@GMT-2003.08.05-12.%02u.00",i); + } + } else { + shadow_copy_data->labels = NULL; + } + + return 0; +} + +/* VFS operations structure */ + +static struct vfs_fn_pointers vfs_test_shadow_copy_fns = { + .get_shadow_copy_data_fn = test_get_shadow_copy_data +}; + +static_decl_vfs; +NTSTATUS vfs_shadow_copy_test_init(TALLOC_CTX *ctx) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, + "shadow_copy_test", + &vfs_test_shadow_copy_fns); +} diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c new file mode 100644 index 0000000..255fa83 --- /dev/null +++ b/examples/VFS/skel_opaque.c @@ -0,0 +1,1099 @@ +/* + * Skeleton VFS module. Implements dummy versions of all VFS + * functions. + * + * Copyright (C) Tim Potter, 1999-2000 + * Copyright (C) Alexander Bokovoy, 2002 + * Copyright (C) Stefan (metze) Metzmacher, 2003 + * Copyright (C) Jeremy Allison 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "../source3/include/includes.h" +#include "lib/util/tevent_unix.h" +#include "lib/util/tevent_ntstatus.h" + +/* PLEASE,PLEASE READ THE VFS MODULES CHAPTER OF THE + SAMBA DEVELOPERS GUIDE!!!!!! + */ + +/* If you take this file as template for your module + * you must re-implement every function. + */ + +static int skel_connect(vfs_handle_struct *handle, const char *service, + const char *user) +{ + errno = ENOSYS; + return -1; +} + +static void skel_disconnect(vfs_handle_struct *handle) +{ + ; +} + +static uint64_t skel_disk_free(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uint64_t *bsize, + uint64_t *dfree, + uint64_t *dsize) +{ + *bsize = 0; + *dfree = 0; + *dsize = 0; + return 0; +} + +static int skel_get_quota(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + enum SMB_QUOTA_TYPE qtype, + unid_t id, + SMB_DISK_QUOTA *dq) +{ + errno = ENOSYS; + return -1; +} + +static int skel_set_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, + unid_t id, SMB_DISK_QUOTA *dq) +{ + errno = ENOSYS; + return -1; +} + +static int skel_get_shadow_copy_data(vfs_handle_struct *handle, + files_struct *fsp, + struct shadow_copy_data *shadow_copy_data, + bool labels) +{ + errno = ENOSYS; + return -1; +} + +static int skel_statvfs(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + struct vfs_statvfs_struct *statbuf) +{ + errno = ENOSYS; + return -1; +} + +static uint32_t skel_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res) +{ + return 0; +} + +static NTSTATUS skel_get_dfs_referrals(struct vfs_handle_struct *handle, + struct dfs_GetDFSReferral *r) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_create_dfs_pathat(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + const struct referral *reflist, + size_t referral_count) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_snap_check_path(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + const char *service_path, + char **base_volume) +{ + return NT_STATUS_NOT_SUPPORTED; +} + +static NTSTATUS skel_snap_create(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + const char *base_volume, + time_t *tstamp, + bool rw, + char **base_path, + char **snap_path) +{ + return NT_STATUS_NOT_SUPPORTED; +} + +static NTSTATUS skel_snap_delete(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + char *base_path, + char *snap_path) +{ + return NT_STATUS_NOT_SUPPORTED; +} + +static DIR *skel_fdopendir(vfs_handle_struct *handle, files_struct *fsp, + const char *mask, uint32_t attr) +{ + return NULL; +} + +static struct dirent *skel_readdir(vfs_handle_struct *handle, + struct files_struct *dirfsp, + DIR *dirp) +{ + return NULL; +} + +static void skel_rewind_dir(vfs_handle_struct *handle, DIR *dirp) +{ + ; +} + +static int skel_mkdirat(vfs_handle_struct *handle, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + mode_t mode) +{ + errno = ENOSYS; + return -1; +} + +static int skel_closedir(vfs_handle_struct *handle, DIR *dir) +{ + errno = ENOSYS; + return -1; +} + +static int skel_openat(struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct files_struct *fsp, + const struct vfs_open_how *how) +{ + if (how->resolve != 0) { + errno = ENOSYS; + return -1; + } + + errno = ENOSYS; + return -1; +} + +static NTSTATUS skel_create_file(struct vfs_handle_struct *handle, + struct smb_request *req, + struct files_struct *dirfsp, + struct smb_filename *smb_fname, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + const struct smb2_lease *lease, + uint64_t allocation_size, + uint32_t private_flags, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct **result, int *pinfo, + const struct smb2_create_blobs *in_context_blobs, + struct smb2_create_blobs *out_context_blobs) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static int skel_close_fn(vfs_handle_struct *handle, files_struct *fsp) +{ + errno = ENOSYS; + return -1; +} + +static ssize_t skel_pread(vfs_handle_struct *handle, files_struct *fsp, + void *data, size_t n, off_t offset) +{ + errno = ENOSYS; + return -1; +} + +static struct tevent_req *skel_pread_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp, + void *data, size_t n, off_t offset) +{ + return NULL; +} + +static ssize_t skel_pread_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + vfs_aio_state->error = ENOSYS; + return -1; +} + +static ssize_t skel_pwrite(vfs_handle_struct *handle, files_struct *fsp, + const void *data, size_t n, off_t offset) +{ + errno = ENOSYS; + return -1; +} + +static struct tevent_req *skel_pwrite_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp, + const void *data, + size_t n, off_t offset) +{ + return NULL; +} + +static ssize_t skel_pwrite_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + vfs_aio_state->error = ENOSYS; + return -1; +} + +static off_t skel_lseek(vfs_handle_struct *handle, files_struct *fsp, + off_t offset, int whence) +{ + errno = ENOSYS; + return (off_t) - 1; +} + +static ssize_t skel_sendfile(vfs_handle_struct *handle, int tofd, + files_struct *fromfsp, const DATA_BLOB *hdr, + off_t offset, size_t n) +{ + errno = ENOSYS; + return -1; +} + +static ssize_t skel_recvfile(vfs_handle_struct *handle, int fromfd, + files_struct *tofsp, off_t offset, size_t n) +{ + errno = ENOSYS; + return -1; +} + +static int skel_renameat(vfs_handle_struct *handle, + files_struct *srcfsp, + const struct smb_filename *smb_fname_src, + files_struct *dstfsp, + const struct smb_filename *smb_fname_dst) +{ + errno = ENOSYS; + return -1; +} + +static struct tevent_req *skel_fsync_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp) +{ + return NULL; +} + +static int skel_fsync_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + vfs_aio_state->error = ENOSYS; + return -1; +} + +static int skel_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname) +{ + errno = ENOSYS; + return -1; +} + +static int skel_fstat(vfs_handle_struct *handle, files_struct *fsp, + SMB_STRUCT_STAT *sbuf) +{ + errno = ENOSYS; + return -1; +} + +static int skel_lstat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) +{ + errno = ENOSYS; + return -1; +} + +static int skel_fstatat( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + SMB_STRUCT_STAT *sbuf, + int flags) +{ + errno = ENOSYS; + return -1; +} + +static uint64_t skel_get_alloc_size(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const SMB_STRUCT_STAT *sbuf) +{ + errno = ENOSYS; + return -1; +} + +static int skel_unlinkat(vfs_handle_struct *handle, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + int flags) +{ + errno = ENOSYS; + return -1; +} + +static int skel_fchmod(vfs_handle_struct *handle, files_struct *fsp, + mode_t mode) +{ + errno = ENOSYS; + return -1; +} + +static int skel_fchown(vfs_handle_struct *handle, files_struct *fsp, + uid_t uid, gid_t gid) +{ + errno = ENOSYS; + return -1; +} + +static int skel_lchown(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) +{ + errno = ENOSYS; + return -1; +} + +static int skel_chdir(vfs_handle_struct *handle, + const struct smb_filename *smb_fname) +{ + errno = ENOSYS; + return -1; +} + +static struct smb_filename *skel_getwd(vfs_handle_struct *handle, + TALLOC_CTX *ctx) +{ + errno = ENOSYS; + return NULL; +} + +static int skel_fntimes(vfs_handle_struct *handle, + files_struct *fsp, + struct smb_file_time *ft) +{ + errno = ENOSYS; + return -1; +} + +static int skel_ftruncate(vfs_handle_struct *handle, files_struct *fsp, + off_t offset) +{ + errno = ENOSYS; + return -1; +} + +static int skel_fallocate(vfs_handle_struct *handle, files_struct *fsp, + uint32_t mode, off_t offset, off_t len) +{ + errno = ENOSYS; + return -1; +} + +static bool skel_lock(vfs_handle_struct *handle, files_struct *fsp, int op, + off_t offset, off_t count, int type) +{ + errno = ENOSYS; + return false; +} + +static int skel_filesystem_sharemode(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t share_mode, + uint32_t access_mask) +{ + errno = ENOSYS; + return -1; +} + +static int skel_fcntl(struct vfs_handle_struct *handle, + struct files_struct *fsp, int cmd, va_list cmd_arg) +{ + errno = ENOSYS; + return -1; +} + +static int skel_linux_setlease(struct vfs_handle_struct *handle, + struct files_struct *fsp, int leasetype) +{ + errno = ENOSYS; + return -1; +} + +static bool skel_getlock(vfs_handle_struct *handle, files_struct *fsp, + off_t *poffset, off_t *pcount, int *ptype, + pid_t *ppid) +{ + errno = ENOSYS; + return false; +} + +static int skel_symlinkat(vfs_handle_struct *handle, + const struct smb_filename *link_contents, + struct files_struct *dirfsp, + const struct smb_filename *new_smb_fname) +{ + errno = ENOSYS; + return -1; +} + +static int skel_vfs_readlinkat(vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + char *buf, + size_t bufsiz) +{ + errno = ENOSYS; + return -1; +} + +static int skel_linkat(vfs_handle_struct *handle, + files_struct *srcfsp, + const struct smb_filename *old_smb_fname, + files_struct *dstfsp, + const struct smb_filename *new_smb_fname, + int flags) +{ + errno = ENOSYS; + return -1; +} + +static int skel_mknodat(vfs_handle_struct *handle, + files_struct *dirfsp, + const struct smb_filename *smb_fname, + mode_t mode, + SMB_DEV_T dev) +{ + errno = ENOSYS; + return -1; +} + +static struct smb_filename *skel_realpath(vfs_handle_struct *handle, + TALLOC_CTX *ctx, + const struct smb_filename *smb_fname) +{ + errno = ENOSYS; + return NULL; +} + +static int skel_fchflags(vfs_handle_struct *handle, + struct files_struct *fsp, + uint flags) +{ + errno = ENOSYS; + return -1; +} + +static struct file_id skel_file_id_create(vfs_handle_struct *handle, + const SMB_STRUCT_STAT *sbuf) +{ + struct file_id id; + ZERO_STRUCT(id); + errno = ENOSYS; + return id; +} + +static uint64_t skel_fs_file_id(vfs_handle_struct *handle, + const SMB_STRUCT_STAT *sbuf) +{ + errno = ENOSYS; + return 0; +} + +struct skel_offload_read_state { + bool dummy; +}; + +static struct tevent_req *skel_offload_read_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t fsctl, + uint32_t ttl, + off_t offset, + size_t to_copy) +{ + struct tevent_req *req = NULL; + struct skel_offload_read_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, struct skel_offload_read_state); + if (req == NULL) { + return NULL; + } + + tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + return tevent_req_post(req, ev); +} + +static NTSTATUS skel_offload_read_recv(struct tevent_req *req, + struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + uint32_t *flags, + uint64_t *xferlen, + DATA_BLOB *_token_blob) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + tevent_req_received(req); + + return NT_STATUS_OK; +} + +struct skel_cc_state { + uint64_t unused; +}; +static struct tevent_req *skel_offload_write_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + uint32_t fsctl, + DATA_BLOB *token, + off_t transfer_offset, + struct files_struct *dest_fsp, + off_t dest_off, + off_t num) +{ + struct tevent_req *req; + struct skel_cc_state *cc_state; + + req = tevent_req_create(mem_ctx, &cc_state, struct skel_cc_state); + if (req == NULL) { + return NULL; + } + + tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + return tevent_req_post(req, ev); +} + +static NTSTATUS skel_offload_write_recv(struct vfs_handle_struct *handle, + struct tevent_req *req, + off_t *copied) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + tevent_req_received(req); + + return NT_STATUS_OK; +} + +static NTSTATUS skel_fget_compression(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *fsp, + uint16_t *_compression_fmt) +{ + return NT_STATUS_INVALID_DEVICE_REQUEST; +} + +static NTSTATUS skel_set_compression(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *fsp, + uint16_t compression_fmt) +{ + return NT_STATUS_INVALID_DEVICE_REQUEST; +} + +static NTSTATUS skel_fstreaminfo(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *mem_ctx, + unsigned int *num_streams, + struct stream_struct **streams) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_get_real_filename_at(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static const char *skel_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) +{ + errno = ENOSYS; + return NULL; +} + +static NTSTATUS skel_brl_lock_windows(struct vfs_handle_struct *handle, + struct byte_range_lock *br_lck, + struct lock_struct *plock) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static bool skel_brl_unlock_windows(struct vfs_handle_struct *handle, + struct byte_range_lock *br_lck, + const struct lock_struct *plock) +{ + errno = ENOSYS; + return false; +} + +static bool skel_strict_lock_check(struct vfs_handle_struct *handle, + struct files_struct *fsp, + struct lock_struct *plock) +{ + errno = ENOSYS; + return false; +} + +static NTSTATUS skel_translate_name(struct vfs_handle_struct *handle, + const char *mapped_name, + enum vfs_translate_direction direction, + TALLOC_CTX *mem_ctx, char **pmapped_name) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_parent_pathname(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + const struct smb_filename *smb_fname_in, + struct smb_filename **parent_dir_out, + struct smb_filename **atname_out) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_fsctl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *ctx, + uint32_t function, + uint16_t req_flags, /* Needed for UNICODE ... */ + const uint8_t *_in_data, + uint32_t in_len, + uint8_t **_out_data, + uint32_t max_out_len, uint32_t *out_len) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_freaddir_attr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *mem_ctx, + struct readdir_attr_data **pattr_data) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +struct skel_get_dos_attributes_state { + struct vfs_aio_state aio_state; + uint32_t dosmode; +}; + +static struct tevent_req *skel_get_dos_attributes_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct vfs_handle_struct *handle, + files_struct *dir_fsp, + struct smb_filename *smb_fname) +{ + struct tevent_req *req = NULL; + struct skel_get_dos_attributes_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct skel_get_dos_attributes_state); + if (req == NULL) { + return NULL; + } + + tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + return tevent_req_post(req, ev); +} + +static NTSTATUS skel_get_dos_attributes_recv(struct tevent_req *req, + struct vfs_aio_state *aio_state, + uint32_t *dosmode) +{ + struct skel_get_dos_attributes_state *state = + tevent_req_data(req, + struct skel_get_dos_attributes_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + *aio_state = state->aio_state; + *dosmode = state->dosmode; + tevent_req_received(req); + return NT_STATUS_OK; +} + +static NTSTATUS skel_fget_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t *dosmode) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_fset_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t dosmode) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32_t security_info, + TALLOC_CTX *mem_ctx, + struct security_descriptor **ppdesc) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32_t security_info_sent, + const struct security_descriptor *psd) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static SMB_ACL_T skel_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + SMB_ACL_TYPE_T type, + TALLOC_CTX *mem_ctx) +{ + errno = ENOSYS; + return (SMB_ACL_T) NULL; +} + +static int skel_sys_acl_blob_get_fd(vfs_handle_struct *handle, + files_struct *fsp, TALLOC_CTX *mem_ctx, + char **blob_description, DATA_BLOB *blob) +{ + errno = ENOSYS; + return -1; +} + +static int skel_sys_acl_set_fd(vfs_handle_struct *handle, + struct files_struct *fsp, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + errno = ENOSYS; + return -1; +} + +static int skel_sys_acl_delete_def_fd(vfs_handle_struct *handle, + struct files_struct *fsp) +{ + errno = ENOSYS; + return -1; +} + +struct skel_getxattrat_state { + struct vfs_aio_state aio_state; + ssize_t xattr_size; + uint8_t *xattr_value; +}; + +static struct tevent_req *skel_getxattrat_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct vfs_handle_struct *handle, + files_struct *dir_fsp, + const struct smb_filename *smb_fname, + const char *xattr_name, + size_t alloc_hint) +{ + struct tevent_req *req = NULL; + struct skel_getxattrat_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct skel_getxattrat_state); + if (req == NULL) { + return NULL; + } + + tevent_req_error(req, ENOSYS); + return tevent_req_post(req, ev); +} + +static ssize_t skel_getxattrat_recv(struct tevent_req *req, + struct vfs_aio_state *aio_state, + TALLOC_CTX *mem_ctx, + uint8_t **xattr_value) +{ + struct skel_getxattrat_state *state = tevent_req_data( + req, struct skel_getxattrat_state); + ssize_t xattr_size; + + if (tevent_req_is_unix_error(req, &aio_state->error)) { + tevent_req_received(req); + return -1; + } + + *aio_state = state->aio_state; + xattr_size = state->xattr_size; + if (xattr_value != NULL) { + *xattr_value = talloc_move(mem_ctx, &state->xattr_value); + } + + tevent_req_received(req); + return xattr_size; +} + +static ssize_t skel_fgetxattr(vfs_handle_struct *handle, + struct files_struct *fsp, const char *name, + void *value, size_t size) +{ + errno = ENOSYS; + return -1; +} + +static ssize_t skel_flistxattr(vfs_handle_struct *handle, + struct files_struct *fsp, char *list, + size_t size) +{ + errno = ENOSYS; + return -1; +} + +static int skel_fremovexattr(vfs_handle_struct *handle, + struct files_struct *fsp, const char *name) +{ + errno = ENOSYS; + return -1; +} + +static int skel_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, + const char *name, const void *value, size_t size, + int flags) +{ + errno = ENOSYS; + return -1; +} + +static bool skel_aio_force(struct vfs_handle_struct *handle, + struct files_struct *fsp) +{ + errno = ENOSYS; + return false; +} + +static NTSTATUS skel_audit_file(struct vfs_handle_struct *handle, + struct smb_filename *file, + struct security_acl *sacl, + uint32_t access_requested, + uint32_t access_denied) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_durable_cookie(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *mem_ctx, + DATA_BLOB *cookie) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_durable_disconnect(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const DATA_BLOB old_cookie, + TALLOC_CTX *mem_ctx, + DATA_BLOB *new_cookie) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS skel_durable_reconnect(struct vfs_handle_struct *handle, + struct smb_request *smb1req, + struct smbXsrv_open *op, + const DATA_BLOB old_cookie, + TALLOC_CTX *mem_ctx, + struct files_struct **fsp, + DATA_BLOB *new_cookie) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/* VFS operations structure */ + +static struct vfs_fn_pointers skel_opaque_fns = { + /* Disk operations */ + + .connect_fn = skel_connect, + .disconnect_fn = skel_disconnect, + .disk_free_fn = skel_disk_free, + .get_quota_fn = skel_get_quota, + .set_quota_fn = skel_set_quota, + .get_shadow_copy_data_fn = skel_get_shadow_copy_data, + .statvfs_fn = skel_statvfs, + .fs_capabilities_fn = skel_fs_capabilities, + .get_dfs_referrals_fn = skel_get_dfs_referrals, + .create_dfs_pathat_fn = skel_create_dfs_pathat, + .read_dfs_pathat_fn = skel_read_dfs_pathat, + .snap_check_path_fn = skel_snap_check_path, + .snap_create_fn = skel_snap_create, + .snap_delete_fn = skel_snap_delete, + + /* Directory operations */ + + .fdopendir_fn = skel_fdopendir, + .readdir_fn = skel_readdir, + .rewind_dir_fn = skel_rewind_dir, + .mkdirat_fn = skel_mkdirat, + .closedir_fn = skel_closedir, + + /* File operations */ + + .openat_fn = skel_openat, + .create_file_fn = skel_create_file, + .close_fn = skel_close_fn, + .pread_fn = skel_pread, + .pread_send_fn = skel_pread_send, + .pread_recv_fn = skel_pread_recv, + .pwrite_fn = skel_pwrite, + .pwrite_send_fn = skel_pwrite_send, + .pwrite_recv_fn = skel_pwrite_recv, + .lseek_fn = skel_lseek, + .sendfile_fn = skel_sendfile, + .recvfile_fn = skel_recvfile, + .renameat_fn = skel_renameat, + .fsync_send_fn = skel_fsync_send, + .fsync_recv_fn = skel_fsync_recv, + .stat_fn = skel_stat, + .fstat_fn = skel_fstat, + .lstat_fn = skel_lstat, + .fstatat_fn = skel_fstatat, + .get_alloc_size_fn = skel_get_alloc_size, + .unlinkat_fn = skel_unlinkat, + .fchmod_fn = skel_fchmod, + .fchown_fn = skel_fchown, + .lchown_fn = skel_lchown, + .chdir_fn = skel_chdir, + .getwd_fn = skel_getwd, + .fntimes_fn = skel_fntimes, + .ftruncate_fn = skel_ftruncate, + .fallocate_fn = skel_fallocate, + .lock_fn = skel_lock, + .filesystem_sharemode_fn = skel_filesystem_sharemode, + .fcntl_fn = skel_fcntl, + .linux_setlease_fn = skel_linux_setlease, + .getlock_fn = skel_getlock, + .symlinkat_fn = skel_symlinkat, + .readlinkat_fn = skel_vfs_readlinkat, + .linkat_fn = skel_linkat, + .mknodat_fn = skel_mknodat, + .realpath_fn = skel_realpath, + .fchflags_fn = skel_fchflags, + .file_id_create_fn = skel_file_id_create, + .fs_file_id_fn = skel_fs_file_id, + .offload_read_send_fn = skel_offload_read_send, + .offload_read_recv_fn = skel_offload_read_recv, + .offload_write_send_fn = skel_offload_write_send, + .offload_write_recv_fn = skel_offload_write_recv, + .fget_compression_fn = skel_fget_compression, + .set_compression_fn = skel_set_compression, + + .fstreaminfo_fn = skel_fstreaminfo, + .get_real_filename_at_fn = skel_get_real_filename_at, + .connectpath_fn = skel_connectpath, + .brl_lock_windows_fn = skel_brl_lock_windows, + .brl_unlock_windows_fn = skel_brl_unlock_windows, + .strict_lock_check_fn = skel_strict_lock_check, + .translate_name_fn = skel_translate_name, + .parent_pathname_fn = skel_parent_pathname, + .fsctl_fn = skel_fsctl, + .freaddir_attr_fn = skel_freaddir_attr, + .audit_file_fn = skel_audit_file, + + /* DOS attributes. */ + .get_dos_attributes_send_fn = skel_get_dos_attributes_send, + .get_dos_attributes_recv_fn = skel_get_dos_attributes_recv, + .fget_dos_attributes_fn = skel_fget_dos_attributes, + .fset_dos_attributes_fn = skel_fset_dos_attributes, + + /* NT ACL operations. */ + + .fget_nt_acl_fn = skel_fget_nt_acl, + .fset_nt_acl_fn = skel_fset_nt_acl, + + /* POSIX ACL operations. */ + + .sys_acl_get_fd_fn = skel_sys_acl_get_fd, + .sys_acl_blob_get_fd_fn = skel_sys_acl_blob_get_fd, + .sys_acl_set_fd_fn = skel_sys_acl_set_fd, + .sys_acl_delete_def_fd_fn = skel_sys_acl_delete_def_fd, + + /* EA operations. */ + .getxattrat_send_fn = skel_getxattrat_send, + .getxattrat_recv_fn = skel_getxattrat_recv, + .fgetxattr_fn = skel_fgetxattr, + .flistxattr_fn = skel_flistxattr, + .fremovexattr_fn = skel_fremovexattr, + .fsetxattr_fn = skel_fsetxattr, + + /* aio operations */ + .aio_force_fn = skel_aio_force, + + /* durable handle operations */ + .durable_cookie_fn = skel_durable_cookie, + .durable_disconnect_fn = skel_durable_disconnect, + .durable_reconnect_fn = skel_durable_reconnect, +}; + +static_decl_vfs; +NTSTATUS vfs_skel_opaque_init(TALLOC_CTX *ctx) +{ + /* + * smb_vfs_assert_all_fns() makes sure every + * call is implemented. + * + * An opaque module requires this! + */ + smb_vfs_assert_all_fns(&skel_opaque_fns, "skel_opaque"); + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "skel_opaque", + &skel_opaque_fns); +} diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c new file mode 100644 index 0000000..461228f --- /dev/null +++ b/examples/VFS/skel_transparent.c @@ -0,0 +1,1410 @@ +/* + * Skeleton VFS module. Implements passthrough operation of all VFS + * calls to disk functions. + * + * Copyright (C) Tim Potter, 1999-2000 + * Copyright (C) Alexander Bokovoy, 2002 + * Copyright (C) Stefan (metze) Metzmacher, 2003 + * Copyright (C) Jeremy Allison 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "../source3/include/includes.h" +#include "lib/util/tevent_unix.h" +#include "lib/util/tevent_ntstatus.h" + +/* PLEASE,PLEASE READ THE VFS MODULES CHAPTER OF THE + SAMBA DEVELOPERS GUIDE!!!!!! + */ + +/* If you take this file as template for your module + * please make sure that you remove all skel_XXX() functions you don't + * want to implement!! The passthrough operations are not + * necessary in a real module. + * + * --metze + */ + +static int skel_connect(vfs_handle_struct *handle, const char *service, + const char *user) +{ + return SMB_VFS_NEXT_CONNECT(handle, service, user); +} + +static void skel_disconnect(vfs_handle_struct *handle) +{ + SMB_VFS_NEXT_DISCONNECT(handle); +} + +static uint64_t skel_disk_free(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uint64_t *bsize, + uint64_t *dfree, + uint64_t *dsize) +{ + return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname, bsize, dfree, dsize); +} + +static int skel_get_quota(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + enum SMB_QUOTA_TYPE qtype, + unid_t id, + SMB_DISK_QUOTA *dq) +{ + return SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname, qtype, id, dq); +} + +static int skel_set_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, + unid_t id, SMB_DISK_QUOTA *dq) +{ + return SMB_VFS_NEXT_SET_QUOTA(handle, qtype, id, dq); +} + +static int skel_get_shadow_copy_data(vfs_handle_struct *handle, + files_struct *fsp, + struct shadow_copy_data *shadow_copy_data, + bool labels) +{ + return SMB_VFS_NEXT_GET_SHADOW_COPY_DATA(handle, fsp, shadow_copy_data, + labels); +} + +static int skel_statvfs(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + struct vfs_statvfs_struct *statbuf) +{ + return SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf); +} + +static uint32_t skel_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res) +{ + return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res); +} + +static NTSTATUS skel_get_dfs_referrals(struct vfs_handle_struct *handle, + struct dfs_GetDFSReferral *r) +{ + return SMB_VFS_NEXT_GET_DFS_REFERRALS(handle, r); +} + +static NTSTATUS skel_create_dfs_pathat(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + const struct referral *reflist, + size_t referral_count) +{ + return SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle, + dirfsp, + smb_fname, + reflist, + referral_count); +} + +static NTSTATUS skel_read_dfs_pathat(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + struct smb_filename *smb_fname, + struct referral **ppreflist, + size_t *preferral_count) +{ + return SMB_VFS_NEXT_READ_DFS_PATHAT(handle, + mem_ctx, + dirfsp, + smb_fname, + ppreflist, + preferral_count); +} + +static NTSTATUS skel_snap_check_path(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + const char *service_path, + char **base_volume) +{ + return SMB_VFS_NEXT_SNAP_CHECK_PATH(handle, mem_ctx, service_path, + base_volume); +} + +static NTSTATUS skel_snap_create(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + const char *base_volume, + time_t *tstamp, + bool rw, + char **base_path, + char **snap_path) +{ + return SMB_VFS_NEXT_SNAP_CREATE(handle, mem_ctx, base_volume, tstamp, + rw, base_path, snap_path); +} + +static NTSTATUS skel_snap_delete(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + char *base_path, + char *snap_path) +{ + return SMB_VFS_NEXT_SNAP_DELETE(handle, mem_ctx, base_path, snap_path); +} + +static DIR *skel_fdopendir(vfs_handle_struct *handle, files_struct *fsp, + const char *mask, uint32_t attr) +{ + return SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr); +} + +static struct dirent * +skel_readdir(vfs_handle_struct *handle, struct files_struct *dirfsp, DIR *dirp) +{ + return SMB_VFS_NEXT_READDIR(handle, dirfsp, dirp); +} + +static void skel_rewind_dir(vfs_handle_struct *handle, DIR *dirp) +{ + SMB_VFS_NEXT_REWINDDIR(handle, dirp); +} + +static int skel_mkdirat(vfs_handle_struct *handle, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + mode_t mode) +{ + return SMB_VFS_NEXT_MKDIRAT(handle, + dirfsp, + smb_fname, + mode); +} + +static int skel_closedir(vfs_handle_struct *handle, DIR *dir) +{ + return SMB_VFS_NEXT_CLOSEDIR(handle, dir); +} + +static int skel_openat(struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + struct files_struct *fsp, + const struct vfs_open_how *how) +{ + return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, how); +} + +static NTSTATUS skel_create_file(struct vfs_handle_struct *handle, + struct smb_request *req, + struct files_struct *dirfsp, + struct smb_filename *smb_fname, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + const struct smb2_lease *lease, + uint64_t allocation_size, + uint32_t private_flags, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct ** result, int *pinfo, + const struct smb2_create_blobs *in_context_blobs, + struct smb2_create_blobs *out_context_blobs) +{ + return SMB_VFS_NEXT_CREATE_FILE(handle, + req, + dirfsp, + smb_fname, + access_mask, + share_access, + create_disposition, + create_options, + file_attributes, + oplock_request, + lease, + allocation_size, + private_flags, + sd, ea_list, result, pinfo, + in_context_blobs, out_context_blobs); +} + +static int skel_close_fn(vfs_handle_struct *handle, files_struct *fsp) +{ + return SMB_VFS_NEXT_CLOSE(handle, fsp); +} + +static ssize_t skel_pread(vfs_handle_struct *handle, files_struct *fsp, + void *data, size_t n, off_t offset) +{ + return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); +} + +struct skel_pread_state { + ssize_t ret; + struct vfs_aio_state vfs_aio_state; +}; + +static void skel_pread_done(struct tevent_req *subreq); + +static struct tevent_req *skel_pread_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp, + void *data, size_t n, off_t offset) +{ + struct tevent_req *req, *subreq; + struct skel_pread_state *state; + + req = tevent_req_create(mem_ctx, &state, struct skel_pread_state); + if (req == NULL) { + return NULL; + } + subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data, + n, offset); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, skel_pread_done, req); + return req; +} + +static void skel_pread_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, struct tevent_req); + struct skel_pread_state *state = + tevent_req_data(req, struct skel_pread_state); + + state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state); + TALLOC_FREE(subreq); + tevent_req_done(req); +} + +static ssize_t skel_pread_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct skel_pread_state *state = + tevent_req_data(req, struct skel_pread_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} + +static ssize_t skel_pwrite(vfs_handle_struct *handle, files_struct *fsp, + const void *data, size_t n, off_t offset) +{ + return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); +} + +struct skel_pwrite_state { + ssize_t ret; + struct vfs_aio_state vfs_aio_state; +}; + +static void skel_pwrite_done(struct tevent_req *subreq); + +static struct tevent_req *skel_pwrite_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp, + const void *data, + size_t n, off_t offset) +{ + struct tevent_req *req, *subreq; + struct skel_pwrite_state *state; + + req = tevent_req_create(mem_ctx, &state, struct skel_pwrite_state); + if (req == NULL) { + return NULL; + } + subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data, + n, offset); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, skel_pwrite_done, req); + return req; +} + +static void skel_pwrite_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, struct tevent_req); + struct skel_pwrite_state *state = + tevent_req_data(req, struct skel_pwrite_state); + + state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state); + TALLOC_FREE(subreq); + tevent_req_done(req); +} + +static ssize_t skel_pwrite_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct skel_pwrite_state *state = + tevent_req_data(req, struct skel_pwrite_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} + +static off_t skel_lseek(vfs_handle_struct *handle, files_struct *fsp, + off_t offset, int whence) +{ + return SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence); +} + +static ssize_t skel_sendfile(vfs_handle_struct *handle, int tofd, + files_struct *fromfsp, const DATA_BLOB *hdr, + off_t offset, size_t n) +{ + return SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp, hdr, offset, n); +} + +static ssize_t skel_recvfile(vfs_handle_struct *handle, int fromfd, + files_struct *tofsp, off_t offset, size_t n) +{ + return SMB_VFS_NEXT_RECVFILE(handle, fromfd, tofsp, offset, n); +} + +static int skel_renameat(vfs_handle_struct *handle, + files_struct *srcfsp, + const struct smb_filename *smb_fname_src, + files_struct *dstfsp, + const struct smb_filename *smb_fname_dst) +{ + return SMB_VFS_NEXT_RENAMEAT(handle, + srcfsp, + smb_fname_src, + dstfsp, + smb_fname_dst); +} + +struct skel_fsync_state { + int ret; + struct vfs_aio_state vfs_aio_state; +}; + +static void skel_fsync_done(struct tevent_req *subreq); + +static struct tevent_req *skel_fsync_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp) +{ + struct tevent_req *req, *subreq; + struct skel_fsync_state *state; + + req = tevent_req_create(mem_ctx, &state, struct skel_fsync_state); + if (req == NULL) { + return NULL; + } + subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, skel_fsync_done, req); + return req; +} + +static void skel_fsync_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, struct tevent_req); + struct skel_fsync_state *state = + tevent_req_data(req, struct skel_fsync_state); + + state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state); + TALLOC_FREE(subreq); + tevent_req_done(req); +} + +static int skel_fsync_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct skel_fsync_state *state = + tevent_req_data(req, struct skel_fsync_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} + +static int skel_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname) +{ + return SMB_VFS_NEXT_STAT(handle, smb_fname); +} + +static int skel_fstat(vfs_handle_struct *handle, files_struct *fsp, + SMB_STRUCT_STAT *sbuf) +{ + return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); +} + +static int skel_lstat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) +{ + return SMB_VFS_NEXT_LSTAT(handle, smb_fname); +} + +static int skel_fstatat( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + SMB_STRUCT_STAT *sbuf, + int flags) +{ + return SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags); +} + +static uint64_t skel_get_alloc_size(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const SMB_STRUCT_STAT *sbuf) +{ + return SMB_VFS_NEXT_GET_ALLOC_SIZE(handle, fsp, sbuf); +} + +static int skel_unlinkat(vfs_handle_struct *handle, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + int flags) +{ + return SMB_VFS_NEXT_UNLINKAT(handle, + dirfsp, + smb_fname, + flags); +} + +static int skel_fchmod(vfs_handle_struct *handle, files_struct *fsp, + mode_t mode) +{ + return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode); +} + +static int skel_fchown(vfs_handle_struct *handle, files_struct *fsp, + uid_t uid, gid_t gid) +{ + return SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid); +} + +static int skel_lchown(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) +{ + return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid); +} + +static int skel_chdir(vfs_handle_struct *handle, + const struct smb_filename *smb_fname) +{ + return SMB_VFS_NEXT_CHDIR(handle, smb_fname); +} + +static struct smb_filename *skel_getwd(vfs_handle_struct *handle, + TALLOC_CTX *ctx) +{ + return SMB_VFS_NEXT_GETWD(handle, ctx); +} + +static int skel_fntimes(vfs_handle_struct *handle, + files_struct *fsp, + struct smb_file_time *ft) +{ + return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft); +} + +static int skel_ftruncate(vfs_handle_struct *handle, files_struct *fsp, + off_t offset) +{ + return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); +} + +static int skel_fallocate(vfs_handle_struct *handle, files_struct *fsp, + uint32_t mode, off_t offset, off_t len) +{ + return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len); +} + +static bool skel_lock(vfs_handle_struct *handle, files_struct *fsp, int op, + off_t offset, off_t count, int type) +{ + return SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type); +} + +static int skel_filesystem_sharemode(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t share_mode, + uint32_t access_mask) +{ + return SMB_VFS_NEXT_FILESYSTEM_SHAREMODE(handle, + fsp, + share_mode, + access_mask); +} + +static int skel_fcntl(struct vfs_handle_struct *handle, + struct files_struct *fsp, int cmd, va_list cmd_arg) +{ + void *arg; + va_list dup_cmd_arg; + int result; + + va_copy(dup_cmd_arg, cmd_arg); + arg = va_arg(dup_cmd_arg, void *); + result = SMB_VFS_NEXT_FCNTL(handle, fsp, cmd, arg); + va_end(dup_cmd_arg); + + return result; +} + +static int skel_linux_setlease(struct vfs_handle_struct *handle, + struct files_struct *fsp, int leasetype) +{ + return SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype); +} + +static bool skel_getlock(vfs_handle_struct *handle, files_struct *fsp, + off_t *poffset, off_t *pcount, int *ptype, + pid_t *ppid) +{ + return SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid); +} + +static int skel_symlinkat(vfs_handle_struct *handle, + const struct smb_filename *link_contents, + struct files_struct *dirfsp, + const struct smb_filename *new_smb_fname) +{ + return SMB_VFS_NEXT_SYMLINKAT(handle, + link_contents, + dirfsp, + new_smb_fname); +} + +static int skel_vfs_readlinkat(vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + char *buf, + size_t bufsiz) +{ + return SMB_VFS_NEXT_READLINKAT(handle, + dirfsp, + smb_fname, + buf, + bufsiz); +} + +static int skel_linkat(vfs_handle_struct *handle, + files_struct *srcfsp, + const struct smb_filename *old_smb_fname, + files_struct *dstfsp, + const struct smb_filename *new_smb_fname, + int flags) +{ + return SMB_VFS_NEXT_LINKAT(handle, + srcfsp, + old_smb_fname, + dstfsp, + new_smb_fname, + flags); +} + +static int skel_mknodat(vfs_handle_struct *handle, + files_struct *dirfsp, + const struct smb_filename *smb_fname, + mode_t mode, + SMB_DEV_T dev) +{ + return SMB_VFS_NEXT_MKNODAT(handle, + dirfsp, + smb_fname, + mode, + dev); +} + +static struct smb_filename *skel_realpath(vfs_handle_struct *handle, + TALLOC_CTX *ctx, + const struct smb_filename *smb_fname) +{ + return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname); +} + +static int skel_fchflags(vfs_handle_struct *handle, + struct files_struct *fsp, + uint flags) +{ + return SMB_VFS_NEXT_FCHFLAGS(handle, fsp, flags); +} + +static struct file_id skel_file_id_create(vfs_handle_struct *handle, + const SMB_STRUCT_STAT *sbuf) +{ + return SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf); +} + +static uint64_t skel_fs_file_id(vfs_handle_struct *handle, + const SMB_STRUCT_STAT *sbuf) +{ + return SMB_VFS_NEXT_FS_FILE_ID(handle, sbuf); +} + +struct skel_offload_read_state { + struct vfs_handle_struct *handle; + uint32_t flags; + uint64_t xferlen; + DATA_BLOB token; +}; + +static void skel_offload_read_done(struct tevent_req *subreq); + +static struct tevent_req *skel_offload_read_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t fsctl, + uint32_t ttl, + off_t offset, + size_t to_copy) +{ + struct tevent_req *req = NULL; + struct skel_offload_read_state *state = NULL; + struct tevent_req *subreq = NULL; + + req = tevent_req_create(mem_ctx, &state, struct skel_offload_read_state); + if (req == NULL) { + return NULL; + } + *state = (struct skel_offload_read_state) { + .handle = handle, + }; + + subreq = SMB_VFS_NEXT_OFFLOAD_READ_SEND(mem_ctx, ev, handle, fsp, + fsctl, ttl, offset, to_copy); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, skel_offload_read_done, req); + return req; +} + +static void skel_offload_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct skel_offload_read_state *state = tevent_req_data( + req, struct skel_offload_read_state); + NTSTATUS status; + + status = SMB_VFS_NEXT_OFFLOAD_READ_RECV(subreq, + state->handle, + state, + &state->flags, + &state->xferlen, + &state->token); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); + return; +} + +static NTSTATUS skel_offload_read_recv(struct tevent_req *req, + struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + uint32_t *flags, + uint64_t *xferlen, + DATA_BLOB *_token) +{ + struct skel_offload_read_state *state = tevent_req_data( + req, struct skel_offload_read_state); + DATA_BLOB token; + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + token = data_blob_talloc(mem_ctx, + state->token.data, + state->token.length); + + tevent_req_received(req); + + if (token.data == NULL) { + return NT_STATUS_NO_MEMORY; + } + + *flags = state->flags; + *xferlen = state->xferlen; + *_token = token; + return NT_STATUS_OK; +} + +struct skel_offload_write_state { + struct vfs_handle_struct *handle; + off_t copied; +}; +static void skel_offload_write_done(struct tevent_req *subreq); + +static struct tevent_req *skel_offload_write_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + uint32_t fsctl, + DATA_BLOB *token, + off_t transfer_offset, + struct files_struct *dest_fsp, + off_t dest_off, + off_t num) +{ + struct tevent_req *req; + struct tevent_req *subreq; + struct skel_offload_write_state *state; + + req = tevent_req_create(mem_ctx, &state, struct skel_offload_write_state); + if (req == NULL) { + return NULL; + } + + state->handle = handle; + subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle, state, ev, + fsctl, token, transfer_offset, + dest_fsp, dest_off, num); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + + tevent_req_set_callback(subreq, skel_offload_write_done, req); + return req; +} + +static void skel_offload_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct skel_offload_write_state *state + = tevent_req_data(req, struct skel_offload_write_state); + NTSTATUS status; + + status = SMB_VFS_NEXT_OFFLOAD_WRITE_RECV(state->handle, + subreq, + &state->copied); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + tevent_req_done(req); +} + +static NTSTATUS skel_offload_write_recv(struct vfs_handle_struct *handle, + struct tevent_req *req, + off_t *copied) +{ + struct skel_offload_write_state *state + = tevent_req_data(req, struct skel_offload_write_state); + NTSTATUS status; + + *copied = state->copied; + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + tevent_req_received(req); + return NT_STATUS_OK; +} + +static NTSTATUS skel_fget_compression(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *fsp, + uint16_t *_compression_fmt) +{ + return SMB_VFS_NEXT_FGET_COMPRESSION(handle, mem_ctx, fsp, + _compression_fmt); +} + +static NTSTATUS skel_set_compression(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *fsp, + uint16_t compression_fmt) +{ + return SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp, + compression_fmt); +} + +static NTSTATUS skel_fstreaminfo(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *mem_ctx, + unsigned int *num_streams, + struct stream_struct **streams) +{ + return SMB_VFS_NEXT_FSTREAMINFO(handle, + fsp, + mem_ctx, + num_streams, + streams); +} + +static NTSTATUS skel_get_real_filename_at(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + return SMB_VFS_NEXT_GET_REAL_FILENAME_AT( + handle, dirfsp, name, mem_ctx, found_name); +} + +static const char *skel_connectpath( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname) +{ + return SMB_VFS_NEXT_CONNECTPATH(handle, dirfsp, smb_fname); +} + +static NTSTATUS skel_brl_lock_windows(struct vfs_handle_struct *handle, + struct byte_range_lock *br_lck, + struct lock_struct *plock) +{ + return SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle, br_lck, plock); +} + +static bool skel_brl_unlock_windows(struct vfs_handle_struct *handle, + struct byte_range_lock *br_lck, + const struct lock_struct *plock) +{ + return SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle, br_lck, plock); +} + +static bool skel_strict_lock_check(struct vfs_handle_struct *handle, + struct files_struct *fsp, + struct lock_struct *plock) +{ + return SMB_VFS_NEXT_STRICT_LOCK_CHECK(handle, fsp, plock); +} + +static NTSTATUS skel_translate_name(struct vfs_handle_struct *handle, + const char *mapped_name, + enum vfs_translate_direction direction, + TALLOC_CTX *mem_ctx, char **pmapped_name) +{ + return SMB_VFS_NEXT_TRANSLATE_NAME(handle, mapped_name, direction, + mem_ctx, pmapped_name); +} + +static NTSTATUS skel_parent_pathname(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + const struct smb_filename *smb_fname_in, + struct smb_filename **parent_dir_out, + struct smb_filename **atname_out) +{ + return SMB_VFS_NEXT_PARENT_PATHNAME(handle, + mem_ctx, + smb_fname_in, + parent_dir_out, + atname_out); +} + +static NTSTATUS skel_fsctl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *ctx, + uint32_t function, + uint16_t req_flags, /* Needed for UNICODE ... */ + const uint8_t *_in_data, + uint32_t in_len, + uint8_t ** _out_data, + uint32_t max_out_len, uint32_t *out_len) +{ + return SMB_VFS_NEXT_FSCTL(handle, + fsp, + ctx, + function, + req_flags, + _in_data, + in_len, _out_data, max_out_len, out_len); +} + +static NTSTATUS skel_freaddir_attr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *mem_ctx, + struct readdir_attr_data **pattr_data) +{ + return SMB_VFS_NEXT_FREADDIR_ATTR(handle, fsp, mem_ctx, pattr_data); +} + +struct skel_get_dos_attributes_state { + struct vfs_aio_state aio_state; + uint32_t dosmode; +}; + +static void skel_get_dos_attributes_done(struct tevent_req *subreq); + +static struct tevent_req *skel_get_dos_attributes_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct vfs_handle_struct *handle, + files_struct *dir_fsp, + struct smb_filename *smb_fname) +{ + struct tevent_req *req = NULL; + struct skel_get_dos_attributes_state *state = NULL; + struct tevent_req *subreq = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct skel_get_dos_attributes_state); + if (req == NULL) { + return NULL; + } + + subreq = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES_SEND(mem_ctx, + ev, + handle, + dir_fsp, + smb_fname); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, skel_get_dos_attributes_done, req); + + return req; +} + +static void skel_get_dos_attributes_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct skel_get_dos_attributes_state *state = + tevent_req_data(req, + struct skel_get_dos_attributes_state); + NTSTATUS status; + + status = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES_RECV(subreq, + &state->aio_state, + &state->dosmode); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); + return; +} + +static NTSTATUS skel_get_dos_attributes_recv(struct tevent_req *req, + struct vfs_aio_state *aio_state, + uint32_t *dosmode) +{ + struct skel_get_dos_attributes_state *state = + tevent_req_data(req, + struct skel_get_dos_attributes_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + *aio_state = state->aio_state; + *dosmode = state->dosmode; + tevent_req_received(req); + return NT_STATUS_OK; +} + +static NTSTATUS skel_fget_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t *dosmode) +{ + return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, + fsp, + dosmode); +} + +static NTSTATUS skel_fset_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t dosmode) +{ + return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, + fsp, + dosmode); +} + +static NTSTATUS skel_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32_t security_info, + TALLOC_CTX *mem_ctx, + struct security_descriptor **ppdesc) +{ + return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, mem_ctx, + ppdesc); +} + +static NTSTATUS skel_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32_t security_info_sent, + const struct security_descriptor *psd) +{ + return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); +} + +static SMB_ACL_T skel_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + SMB_ACL_TYPE_T type, + TALLOC_CTX *mem_ctx) +{ + return SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, type, mem_ctx); +} + +static int skel_sys_acl_blob_get_fd(vfs_handle_struct *handle, + files_struct *fsp, TALLOC_CTX *mem_ctx, + char **blob_description, DATA_BLOB *blob) +{ + return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx, + blob_description, blob); +} + +static int skel_sys_acl_set_fd(vfs_handle_struct *handle, + struct files_struct *fsp, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, type, theacl); +} + +static int skel_sys_acl_delete_def_fd(vfs_handle_struct *handle, + struct files_struct *fsp) +{ + return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FD(handle, fsp); +} + +struct skel_getxattrat_state { + struct vfs_aio_state aio_state; + ssize_t xattr_size; + uint8_t *xattr_value; +}; + +static void skel_getxattrat_done(struct tevent_req *subreq); + +static struct tevent_req *skel_getxattrat_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct vfs_handle_struct *handle, + files_struct *dir_fsp, + const struct smb_filename *smb_fname, + const char *xattr_name, + size_t alloc_hint) +{ + struct tevent_req *req = NULL; + struct skel_getxattrat_state *state = NULL; + struct tevent_req *subreq = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct skel_getxattrat_state); + if (req == NULL) { + return NULL; + } + + subreq = SMB_VFS_NEXT_GETXATTRAT_SEND(state, + ev, + handle, + dir_fsp, + smb_fname, + xattr_name, + alloc_hint); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, skel_getxattrat_done, req); + + return req; +} + +static void skel_getxattrat_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct skel_getxattrat_state *state = tevent_req_data( + req, struct skel_getxattrat_state); + + state->xattr_size = SMB_VFS_NEXT_GETXATTRAT_RECV(subreq, + &state->aio_state, + state, + &state->xattr_value); + TALLOC_FREE(subreq); + if (state->xattr_size == -1) { + tevent_req_error(req, state->aio_state.error); + return; + } + + tevent_req_done(req); +} + +static ssize_t skel_getxattrat_recv(struct tevent_req *req, + struct vfs_aio_state *aio_state, + TALLOC_CTX *mem_ctx, + uint8_t **xattr_value) +{ + struct skel_getxattrat_state *state = tevent_req_data( + req, struct skel_getxattrat_state); + ssize_t xattr_size; + + if (tevent_req_is_unix_error(req, &aio_state->error)) { + tevent_req_received(req); + return -1; + } + + *aio_state = state->aio_state; + xattr_size = state->xattr_size; + if (xattr_value != NULL) { + *xattr_value = talloc_move(mem_ctx, &state->xattr_value); + } + + tevent_req_received(req); + return xattr_size; +} + +static ssize_t skel_fgetxattr(vfs_handle_struct *handle, + struct files_struct *fsp, const char *name, + void *value, size_t size) +{ + return SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size); +} + +static ssize_t skel_flistxattr(vfs_handle_struct *handle, + struct files_struct *fsp, char *list, + size_t size) +{ + return SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size); +} + +static int skel_fremovexattr(vfs_handle_struct *handle, + struct files_struct *fsp, const char *name) +{ + return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name); +} + +static int skel_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, + const char *name, const void *value, size_t size, + int flags) +{ + return SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags); +} + +static bool skel_aio_force(struct vfs_handle_struct *handle, + struct files_struct *fsp) +{ + return SMB_VFS_NEXT_AIO_FORCE(handle, fsp); +} + +static NTSTATUS skel_audit_file(struct vfs_handle_struct *handle, + struct smb_filename *file, + struct security_acl *sacl, + uint32_t access_requested, + uint32_t access_denied) +{ + return SMB_VFS_NEXT_AUDIT_FILE(handle, + file, + sacl, + access_requested, + access_denied); +} + +static NTSTATUS skel_durable_cookie(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *mem_ctx, + DATA_BLOB *cookie) +{ + return SMB_VFS_NEXT_DURABLE_COOKIE(handle, + fsp, + mem_ctx, + cookie); +} + +static NTSTATUS skel_durable_disconnect(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const DATA_BLOB old_cookie, + TALLOC_CTX *mem_ctx, + DATA_BLOB *new_cookie) +{ + return SMB_VFS_NEXT_DURABLE_DISCONNECT(handle, + fsp, + old_cookie, + mem_ctx, + new_cookie); +} + +static NTSTATUS skel_durable_reconnect(struct vfs_handle_struct *handle, + struct smb_request *smb1req, + struct smbXsrv_open *op, + const DATA_BLOB old_cookie, + TALLOC_CTX *mem_ctx, + struct files_struct **fsp, + DATA_BLOB *new_cookie) +{ + return SMB_VFS_NEXT_DURABLE_RECONNECT(handle, + smb1req, + op, + old_cookie, + mem_ctx, + fsp, + new_cookie); +} + +/* VFS operations structure */ + +static struct vfs_fn_pointers skel_transparent_fns = { + /* Disk operations */ + + .connect_fn = skel_connect, + .disconnect_fn = skel_disconnect, + .disk_free_fn = skel_disk_free, + .get_quota_fn = skel_get_quota, + .set_quota_fn = skel_set_quota, + .get_shadow_copy_data_fn = skel_get_shadow_copy_data, + .statvfs_fn = skel_statvfs, + .fs_capabilities_fn = skel_fs_capabilities, + .get_dfs_referrals_fn = skel_get_dfs_referrals, + .create_dfs_pathat_fn = skel_create_dfs_pathat, + .read_dfs_pathat_fn = skel_read_dfs_pathat, + .snap_check_path_fn = skel_snap_check_path, + .snap_create_fn = skel_snap_create, + .snap_delete_fn = skel_snap_delete, + + /* Directory operations */ + + .fdopendir_fn = skel_fdopendir, + .readdir_fn = skel_readdir, + .rewind_dir_fn = skel_rewind_dir, + .mkdirat_fn = skel_mkdirat, + .closedir_fn = skel_closedir, + + /* File operations */ + + .openat_fn = skel_openat, + .create_file_fn = skel_create_file, + .close_fn = skel_close_fn, + .pread_fn = skel_pread, + .pread_send_fn = skel_pread_send, + .pread_recv_fn = skel_pread_recv, + .pwrite_fn = skel_pwrite, + .pwrite_send_fn = skel_pwrite_send, + .pwrite_recv_fn = skel_pwrite_recv, + .lseek_fn = skel_lseek, + .sendfile_fn = skel_sendfile, + .recvfile_fn = skel_recvfile, + .renameat_fn = skel_renameat, + .fsync_send_fn = skel_fsync_send, + .fsync_recv_fn = skel_fsync_recv, + .stat_fn = skel_stat, + .fstat_fn = skel_fstat, + .lstat_fn = skel_lstat, + .fstatat_fn = skel_fstatat, + .get_alloc_size_fn = skel_get_alloc_size, + .unlinkat_fn = skel_unlinkat, + .fchmod_fn = skel_fchmod, + .fchown_fn = skel_fchown, + .lchown_fn = skel_lchown, + .chdir_fn = skel_chdir, + .getwd_fn = skel_getwd, + .fntimes_fn = skel_fntimes, + .ftruncate_fn = skel_ftruncate, + .fallocate_fn = skel_fallocate, + .lock_fn = skel_lock, + .filesystem_sharemode_fn = skel_filesystem_sharemode, + .fcntl_fn = skel_fcntl, + .linux_setlease_fn = skel_linux_setlease, + .getlock_fn = skel_getlock, + .symlinkat_fn = skel_symlinkat, + .readlinkat_fn = skel_vfs_readlinkat, + .linkat_fn = skel_linkat, + .mknodat_fn = skel_mknodat, + .realpath_fn = skel_realpath, + .fchflags_fn = skel_fchflags, + .file_id_create_fn = skel_file_id_create, + .fs_file_id_fn = skel_fs_file_id, + .offload_read_send_fn = skel_offload_read_send, + .offload_read_recv_fn = skel_offload_read_recv, + .offload_write_send_fn = skel_offload_write_send, + .offload_write_recv_fn = skel_offload_write_recv, + .fget_compression_fn = skel_fget_compression, + .set_compression_fn = skel_set_compression, + + .fstreaminfo_fn = skel_fstreaminfo, + .get_real_filename_at_fn = skel_get_real_filename_at, + .connectpath_fn = skel_connectpath, + .brl_lock_windows_fn = skel_brl_lock_windows, + .brl_unlock_windows_fn = skel_brl_unlock_windows, + .strict_lock_check_fn = skel_strict_lock_check, + .translate_name_fn = skel_translate_name, + .parent_pathname_fn = skel_parent_pathname, + .fsctl_fn = skel_fsctl, + .freaddir_attr_fn = skel_freaddir_attr, + .audit_file_fn = skel_audit_file, + + /* DOS attributes. */ + .get_dos_attributes_send_fn = skel_get_dos_attributes_send, + .get_dos_attributes_recv_fn = skel_get_dos_attributes_recv, + .fget_dos_attributes_fn = skel_fget_dos_attributes, + .fset_dos_attributes_fn = skel_fset_dos_attributes, + + /* NT ACL operations. */ + + .fget_nt_acl_fn = skel_fget_nt_acl, + .fset_nt_acl_fn = skel_fset_nt_acl, + + /* POSIX ACL operations. */ + + .sys_acl_get_fd_fn = skel_sys_acl_get_fd, + .sys_acl_blob_get_fd_fn = skel_sys_acl_blob_get_fd, + .sys_acl_set_fd_fn = skel_sys_acl_set_fd, + .sys_acl_delete_def_fd_fn = skel_sys_acl_delete_def_fd, + + /* EA operations. */ + .getxattrat_send_fn = skel_getxattrat_send, + .getxattrat_recv_fn = skel_getxattrat_recv, + .fgetxattr_fn = skel_fgetxattr, + .flistxattr_fn = skel_flistxattr, + .fremovexattr_fn = skel_fremovexattr, + .fsetxattr_fn = skel_fsetxattr, + + /* aio operations */ + .aio_force_fn = skel_aio_force, + + /* durable handle operations */ + .durable_cookie_fn = skel_durable_cookie, + .durable_disconnect_fn = skel_durable_disconnect, + .durable_reconnect_fn = skel_durable_reconnect, +}; + +static_decl_vfs; +NTSTATUS vfs_skel_transparent_init(TALLOC_CTX *ctx) +{ + /* + * smb_vfs_assert_all_fns() is only needed in + * order to have a complete example. + * + * A transparent vfs module typically don't + * need to implement every calls. + */ + smb_vfs_assert_all_fns(&skel_transparent_fns, "skel_transparent"); + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "skel_transparent", + &skel_transparent_fns); +} diff --git a/examples/VFS/wscript_build b/examples/VFS/wscript_build new file mode 100644 index 0000000..92fea70 --- /dev/null +++ b/examples/VFS/wscript_build @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +bld.SAMBA3_MODULE('vfs_skel_opaque', + subsystem='vfs', + source='skel_opaque.c', + deps='samba-util', + init_function='', + internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_skel_opaque'), + enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_skel_opaque')) + +bld.SAMBA3_MODULE('vfs_skel_transparent', + subsystem='vfs', + source='skel_transparent.c', + deps='samba-util', + init_function='', + internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_skel_transparent'), + enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_skel_transparent')) + +bld.SAMBA3_MODULE('vfs_shadow_copy_test', + subsystem='vfs', + source='shadow_copy_test.c', + deps='samba-util', + init_function='', + internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_shadow_copy_test'), + enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_shadow_copy_test')) diff --git a/examples/ad-bench/README b/examples/ad-bench/README new file mode 100644 index 0000000..de6235f --- /dev/null +++ b/examples/ad-bench/README @@ -0,0 +1,42 @@ +========================== +Active Directory benchmark +========================== + +Setup +===== + +You need to modify settings.sh to point to the correct binaries for your +platform. One thing you might want to do in order to be able to run the +benchmark as a non-root user is to compile your own samba version with the +--prefix configure option set to some location writeable by the user who will be +running the benchmark. You then need to point the NET variable to the correct +location. + +Most likely, you will also want to put the realm to kdc hostname mappings into +krb5.conf and the hostname to IP address mappings for the kdcs to test into the +hosts file, so you actually benchmark the AD speed, not DNS lookup speed. + +Running the benchmarks +====================== + +Per default, the benchmark looks for a file called runs.txt in the directory the +benchmark is run from. (This is configurable in the settings.sh file) +runs.txt contains the credentials and server names to connect to, one set of +credentials/server per line. The format is as follows: + +user@REALM.EXAMPLE.COM%password:domain_controller_host_name + +License +======= +AD-Bench is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +AD-Bench is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. diff --git a/examples/ad-bench/ad-bench.sh b/examples/ad-bench/ad-bench.sh new file mode 100755 index 0000000..c4c2a4a --- /dev/null +++ b/examples/ad-bench/ad-bench.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# AD-Bench main program, runs all the benchmarks +# +# Copyright (C) 2009 Kai Blin <kai@samba.org> +# +# This file is part of AD-Bench, an Active Directory benchmark tool +# +# AD-Bench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# AD-Bench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. + +source $(dirname $0)/utils.sh + +if [ ! -f $RUNS ]; then + echo "Error: please fill in $RUNS" + echo "Sambple entries are" + echo "user@REALM.EXAMPLE.COM%password:domain_controller" + exit 1 +fi + +for run in $(cat $RUNS); do + echo "START RUN" + bash $(dirname $0)/time_kinit.sh $(echo $run | cut -d ":" -f 1) + bash $(dirname $0)/time_join.sh $(echo $run | cut -d ":" -f 1) $(echo $run | cut -d ":" -f 2) + bash $(dirname $0)/time_user.sh $(echo $run | cut -d ":" -f 1) $(echo $run | cut -d ":" -f 2) + bash $(dirname $0)/time_group.sh $(echo $run | cut -d ":" -f 1) $(echo $run | cut -d ":" -f 2) + bash $(dirname $0)/time_ldap.sh $(echo $run | cut -d ":" -f 1) $(echo $run | cut -d ":" -f 2) + echo "END RUN" +done diff --git a/examples/ad-bench/settings.sh b/examples/ad-bench/settings.sh new file mode 100644 index 0000000..b4a68ae --- /dev/null +++ b/examples/ad-bench/settings.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# AD-Bench settings +# +# Copyright (C) 2009 Kai Blin <kai@samba.org> +# +# This file is part of AD-Bench, an Active Directory benchmark tool +# +# AD-Bench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# AD-Bench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. + +DATE=date +BC=bc +SED=sed +DATE_FORMATSTR="+%s.%N" + +KINIT=kinit +# MIT krb < 1.6 +KINIT_PARAM_OLD="--password-file=STDIN" +# MIT krb >= 1.6 +KINIT_PARAM_NEW="" + +KDESTROY=kdestroy +SEQ=seq + +NEW_KRB5CCNAME=/tmp/ad_test_ccname + +NET="${HOME}/samba/bin/net" +CONFIG_FILE=$(dirname $0)/smb.conf + +RUNS=$(dirname $0)/runs.txt diff --git a/examples/ad-bench/test_utils.sh b/examples/ad-bench/test_utils.sh new file mode 100644 index 0000000..2580c9d --- /dev/null +++ b/examples/ad-bench/test_utils.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# AD-Bench utility function tests +# +# Copyright (C) 2009 Kai Blin <kai@samba.org> +# +# This file is part of AD-Bench, an Active Directory benchmark tool +# +# AD-Bench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# AD-Bench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. + +source $(dirname $0)/utils.sh + +INPUT="administrator@AD.EXAMPLE.COM%secret" +echo "Principal for $INPUT is " $(get_principal $INPUT) +echo "Password for $INPUT is " $(get_password $INPUT) +echo "Realm for $INPUT is " $(get_realm $INPUT) +echo "NT_DOM for $INPUT is " $(get_nt_dom $INPUT) + +echo "Padding 2: " $(pad_number 1 2) " 4: " $(pad_number 23 4) diff --git a/examples/ad-bench/time_group.sh b/examples/ad-bench/time_group.sh new file mode 100644 index 0000000..be47aac --- /dev/null +++ b/examples/ad-bench/time_group.sh @@ -0,0 +1,131 @@ +#!/bin/bash +# AD-Bench group add/remove benchmark +# +# Copyright (C) 2009 Kai Blin <kai@samba.org> +# +# This file is part of AD-Bench, an Active Directory benchmark tool +# +# AD-Bench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# AD-Bench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. + +ITERATIONS=100 + +source $(dirname $0)/utils.sh + +PRINCIPAL=$(get_principal $1) +PASSWORD=$(get_password $1) +REALM=$(get_realm $1) +NT_DOM=$(get_nt_dom $1) +SERVER=$2 + +add_group() +{ + GROUP=$1 + ${NET} ads group add "${GROUP}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} ads group add returned error: $RET" + exit 1 + fi +} + +del_group() +{ + GROUP=$1 + ${NET} ads group delete "${GROUP}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +enum_group() +{ + ${NET} ads group -k --configfile=$CONFIG_FILE -S $SERVER >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +info_group() +{ + GROUP=$1 + ${NET} ads group info "${GROUP}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +set_up() +{ + set_krb_env + setup_kinit + call_kinit "${PRINCIPAL}" "${PASSWORD}" + write_configfile "${REALM}" "${NT_DOM}" +} + +tear_down() +{ + ${KDESTROY} + restore_krb_env +} + +set_up + +echo -e "\tGROUP $SERVER" + +START_TIME=$(start_timer) + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + GROUP=$(echo "ad_test_$(pad_number $i 3)") + add_group $GROUP + echo -n "." +done +echo "done" + +enum_group + +# Requires winbind, which requires root perms to start. Skip this for now +#echo -en "\t" +#for i in $( ${SEQ} 1 $ITERATIONS ); do +# GROUP=$( echo "ad_test_$(pad_number $i 3)" ) +# info_group $GROUP +# echo -n "." +#done +#echo "done" + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + GROUP=$(echo "ad_test_$(pad_number $i 3)") + del_group $GROUP + echo -n "." +done +echo "done" + +STOP_TIME=$(stop_timer) + +TOTAL_TIME=$(total_time $START_TIME $STOP_TIME) + +echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s" + +LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS) + +echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE" + +tear_down diff --git a/examples/ad-bench/time_join.sh b/examples/ad-bench/time_join.sh new file mode 100644 index 0000000..2545a9f --- /dev/null +++ b/examples/ad-bench/time_join.sh @@ -0,0 +1,89 @@ +#!/bin/bash +# AD-Bench Machine join/part benchmark +# +# Copyright (C) 2009 Kai Blin <kai@samba.org> +# +# This file is part of AD-Bench, an Active Directory benchmark tool +# +# AD-Bench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# AD-Bench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. + +ITERATIONS=100 + +source $(dirname $0)/utils.sh + +PRINCIPAL=$(get_principal $1) +PASSWORD=$(get_password $1) +REALM=$(get_realm $1) +NT_DOM=$(get_nt_dom $1) + +join_domain() +{ + SERVER=$1 + ${NET} ads join -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +leave_domain() +{ + SERVER=$1 + ${NET} ads leave -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +set_up() +{ + set_krb_env + setup_kinit + call_kinit "${PRINCIPAL}" "${PASSWORD}" + write_configfile "${REALM}" "${NT_DOM}" +} + +tear_down() +{ + ${KDESTROY} + restore_krb_env +} + +set_up + +echo -e "\tJOIN $2" + +START_TIME=$(start_timer) + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + join_domain $2 + leave_domain $2 + echo -n "." +done +echo "done" + +STOP_TIME=$(stop_timer) + +TOTAL_TIME=$(total_time $START_TIME $STOP_TIME) + +echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s" + +LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS) + +echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE" + +tear_down diff --git a/examples/ad-bench/time_kinit.sh b/examples/ad-bench/time_kinit.sh new file mode 100644 index 0000000..b2e0030 --- /dev/null +++ b/examples/ad-bench/time_kinit.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# AD-Bench Kerberos ticket benchmark +# +# Copyright (C) 2009 Kai Blin <kai@samba.org> +# +# This file is part of AD-Bench, an Active Directory benchmark tool. +# +# AD-Bench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# AD-Bench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. + +# Iterations are set per test, so more time-consuming tests can be run less +# often +ITERATIONS=100 + +source $(dirname $0)/utils.sh + +set_up() +{ + set_krb_env + setup_kinit +} + +tear_down() +{ + restore_krb_env +} + +set_up + +PRINCIPAL=$(get_principal $1) +PASSWORD=$(get_password $1) + +echo -e "\tKINIT ${PRINCIPAL}" + +START_TIME=$(start_timer) + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + call_kinit "${PRINCIPAL}" "${PASSWORD}" + ${KDESTROY} + echo -n "." +done +echo "done" + +STOP_TIME=$(stop_timer) + +TOTAL_TIME=$(total_time $START_TIME $STOP_TIME) + +echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s" + +LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS) + +echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE" + +tear_down diff --git a/examples/ad-bench/time_ldap.sh b/examples/ad-bench/time_ldap.sh new file mode 100644 index 0000000..4af6ef1 --- /dev/null +++ b/examples/ad-bench/time_ldap.sh @@ -0,0 +1,144 @@ +#!/bin/bash + +ITERATIONS=100 + +source $(dirname $0)/utils.sh + +PRINCIPAL=$(get_principal $1) +PASSWORD=$(get_password $1) +REALM=$(get_realm $1) +NT_DOM=$(get_nt_dom $1) +SERVER=$2 + +search_users() +{ + ${NET} ads search '(objectCategory=user)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +search_groups() +{ + ${NET} ads search '(objectCategory=group)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +search_computers() +{ + ${NET} ads search '(objectCategory=computer)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +search_wildcard() +{ + ${NET} ads search '(objectCategory=*)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +search_unindexed() +{ + ${NET} ads search '(description=Built-in account for adminstering the computer/domain)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +set_up() +{ + set_krb_env + setup_kinit + call_kinit "${PRINCIPAL}" "${PASSWORD}" + write_configfile "${REALM}" "${NT_DOM}" +} + +tear_down() +{ + ${KDESTROY} + restore_krb_env +} + +set_up + +echo -e "\tSEARCH INDEXED $2" + +START_TIME=$(start_timer) + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + search_users + search_groups + search_computers + echo -n "." +done +echo "done" + +STOP_TIME=$(stop_timer) + +TOTAL_TIME=$(total_time $START_TIME $STOP_TIME) + +echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s" + +LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS) + +echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE" + +######################## + +echo -e "\tSEARCH WILDCARD $2" + +START_TIME=$(start_timer) + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + search_wildcard + echo -n "." +done +echo "done" + +STOP_TIME=$(stop_timer) + +TOTAL_TIME=$(total_time $START_TIME $STOP_TIME) + +echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s" + +LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS) + +echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE" + +######################## + +echo -e "\tSEARCH UNINDEXED $2" + +START_TIME=$(start_timer) + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + search_unindexed + echo -n "." +done +echo "done" + +STOP_TIME=$(stop_timer) + +TOTAL_TIME=$(total_time $START_TIME $STOP_TIME) + +echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s" + +LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS) + +echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE" + +tear_down diff --git a/examples/ad-bench/time_user.sh b/examples/ad-bench/time_user.sh new file mode 100644 index 0000000..5fedb7a --- /dev/null +++ b/examples/ad-bench/time_user.sh @@ -0,0 +1,131 @@ +#!/bin/bash +# AD-Bench user add/remove benchmark +# +# Copyright (C) 2009 Kai Blin <kai@samba.org> +# +# This file is part of AD-Bench, an Active Directory benchmark tool +# +# AD-Bench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# AD-Bench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. + +ITERATIONS=100 + +source $(dirname $0)/utils.sh + +PRINCIPAL=$(get_principal $1) +PASSWORD=$(get_password $1) +REALM=$(get_realm $1) +NT_DOM=$(get_nt_dom $1) +SERVER=$2 + +add_user() +{ + USER=$1 + ${NET} ads user add "${USER}" 'Sup3rS3cr3T!' -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} ads user add returned error: $RET" + exit 1 + fi +} + +del_user() +{ + USER=$1 + ${NET} ads user delete "${USER}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +enum_user() +{ + ${NET} ads user -k --configfile=$CONFIG_FILE -S $SERVER >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +info_user() +{ + USER=$1 + ${NET} ads user info "${USER}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "${NET} returned error: $RET" + exit 1 + fi +} + +set_up() +{ + set_krb_env + setup_kinit + call_kinit "${PRINCIPAL}" "${PASSWORD}" + write_configfile "${REALM}" "${NT_DOM}" +} + +tear_down() +{ + ${KDESTROY} + restore_krb_env +} + +set_up + +echo -e "\tUSER $SERVER" + +START_TIME=$(start_timer) + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + USER=$(echo "ad_test_$(pad_number $i 3)") + add_user $USER + echo -n "." +done +echo "done" + +enum_user + +# Requires winbind, which requires root perms to start. Skip this for now +#echo -en "\t" +#for i in $( ${SEQ} 1 $ITERATIONS ); do +# USER=$( echo "ad_test_$(pad_number $i 3)" ) +# info_user $USER +# echo -n "." +#done +#echo "done" + +echo -en "\t" +for i in $(${SEQ} 1 $ITERATIONS); do + USER=$(echo "ad_test_$(pad_number $i 3)") + del_user $USER + echo -n "." +done +echo "done" + +STOP_TIME=$(stop_timer) + +TOTAL_TIME=$(total_time $START_TIME $STOP_TIME) + +echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s" + +LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS) + +echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE" + +tear_down diff --git a/examples/ad-bench/utils.sh b/examples/ad-bench/utils.sh new file mode 100644 index 0000000..5a7c015 --- /dev/null +++ b/examples/ad-bench/utils.sh @@ -0,0 +1,130 @@ +#!/bin/bash +# AD-Bench utility functions +# +# Copyright (C) 2009 Kai Blin <kai@samba.org> +# +# This file is part of AD-Bench, an Active Directory benchmark tool +# +# AD-Bench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# AD-Bench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AD-Bench. If not, see <http://www.gnu.org/licenses/>. + +source $(dirname $0)/settings.sh + +start_timer() +{ + START_TIME=$(${DATE} ${DATE_FORMATSTR}) + echo "$START_TIME" +} + +stop_timer() +{ + STOP_TIME=$(${DATE} ${DATE_FORMATSTR}) + echo "$STOP_TIME" +} + +total_time() +{ + START_TIME=$1 + END_TIME=$2 + TOTAL_TIME=$(echo "scale=9;$STOP_TIME - $START_TIME" | ${BC}) + echo "$TOTAL_TIME" +} + +iterations_per_minute() +{ + START_TIME=$1 + STOP_TIME=$2 + TOTAL_RUNS=$3 + + TOTAL_TIME=$(total_time $START_TIME $STOP_TIME) + + ITER_PER_MIN=$(echo "scale=2; 60 * $TOTAL_RUNS / $TOTAL_TIME" | ${BC}) + echo "$ITER_PER_MIN" +} + +get_principal() +{ + PRINCIPAL=$(echo $1 | ${SED} -e "s/\(.*\)%.*/\1/") + echo "$PRINCIPAL" +} + +get_password() +{ + PASSWORD=$(echo $1 | ${SED} -e "s/.*%\(.*\)/\1/") + echo "$PASSWORD" +} + +get_realm() +{ + REALM=$(echo $1 | ${SED} -e "s/.*@\(.*\)%.*/\1/") + echo "$REALM" +} + +get_nt_dom() +{ + NT_DOM=$(echo $1 | ${SED} -e "s/.*@\([A-Z1-9-]*\)\..*/\1/") + echo "$NT_DOM" +} + +set_krb_env() +{ + OLD_KRB5CCNAME="${KRB5CCNAME}" + KRB5CCNAME="${NEW_KRB5CCNAME}" + export KRB5CCNAME +} + +restore_krb_env() +{ + KRB5CCNAME="${OLD_KRB5CCNAME}" + export KRB5CCNAME +} + +setup_kinit() +{ + ${KINIT} --invalid 2>&1 | grep -q "password-file" + if [ $? -eq 0 ]; then + KINIT="${KINIT} ${KINIT_PARAM_OLD}" + else + KINIT="${KINIT} ${KINIT_PARAM_NEW}" + fi +} + +write_configfile() +{ + REALM=$1 + NT_DOM=$2 + echo -e "[global]" >$CONFIG_FILE + echo -e "\trealm = $REALM" >>$CONFIG_FILE + echo -e "\tworkgroup = $NT_DOM" >>$CONFIG_FILE + echo -e "\tsecurity = ADS" >>$CONFIG_FILE +} + +call_kinit() +{ + PRINCIPAL=$1 + PASSWORD=$2 + echo "${PASSWORD}" | ${KINIT} ${PRINCIPAL} >/dev/null + RET=$? + if [ $RET -ne 0 ]; then + echo "kinit returned an error: $RET" + exit 1 + fi +} + +pad_number() +{ + NUMBER=$1 + DIGITS=$2 + PADDED_NO=$(printf "%0${DIGITS}d" $NUMBER) + echo $PADDED_NO +} diff --git a/examples/auth/crackcheck/Makefile b/examples/auth/crackcheck/Makefile new file mode 100644 index 0000000..edc7645 --- /dev/null +++ b/examples/auth/crackcheck/Makefile @@ -0,0 +1,25 @@ +# C compiler +#CC=cc +CC=gcc + +# Uncomment the following to add symbols to the code for debugging +#DEBUG=-g -Wall + +# Optimization for the compiler +#OPTIMIZE= +OPTIMIZE=-O2 + +CFLAGS= $(DEBUG) $(OPTIMIZE) + +OBJS = crackcheck.o +LIBS = -lcrack + +crackcheck: $(OBJS) + $(CC) $(CFLAGS) -o crackcheck $(OBJS) $(LIBS) + +clean: + rm -f core *.o crackcheck + +install: crackcheck + install -m 555 crackcheck $(PREFIX)/sbin/crackcheck + diff --git a/examples/auth/crackcheck/crackcheck.c b/examples/auth/crackcheck/crackcheck.c new file mode 100644 index 0000000..c303775 --- /dev/null +++ b/examples/auth/crackcheck/crackcheck.c @@ -0,0 +1,141 @@ +#include <memory.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <crack.h> +#include <unistd.h> + +void usage(char *command) { + char *c, *comm; + + comm = command; + while ((c = strrchr(comm, '/')) != NULL) { + comm = c + 1; + } + + fprintf(stderr, "Usage: %s [-c] [-s] [-d <dictionary>]\n\n", comm); + fprintf(stderr, " -c enables NT like complexity checks\n"); + fprintf(stderr, " -d <dictionary file> for cracklib\n"); + fprintf(stderr, " -s simple check use NT like checks ONLY\n\n"); + fprintf(stderr, "The password is read via stdin.\n\n"); + exit(-1); +} + +int complexity(char* passwd) +{ + /* TG 26.10.2005 + * check password for complexity like MS Windows NT + */ + + int c_upper = 0; + int c_lower = 0; + int c_digit = 0; + int c_punct = 0; + int c_tot = 0; + int i, len; + + if (!passwd) goto fail; + len = strlen(passwd); + + for (i = 0; i < len; i++) { + + if (c_tot >= 3) break; + + if (isupper(passwd[i])) { + if (!c_upper) { + c_upper = 1; + c_tot += 1; + } + continue; + } + if (islower(passwd[i])) { + if (!c_lower) { + c_lower = 1; + c_tot += 1; + } + continue; + } + if (isdigit(passwd[i])) { + if (!c_digit) { + c_digit = 1; + c_tot += 1; + } + continue; + } + if (ispunct(passwd[i])) { + if (!c_punct) { + c_punct = 1; + c_tot += 1; + } + continue; + } + } + + if ((c_tot) < 3) goto fail; + return 0; + +fail: + fprintf(stderr, "ERR Complexity check failed\n\n"); + return -4; +} + +int main(int argc, char **argv) { + extern char *optarg; + int c, ret, complex_check = 0, simplex_check = 0; + + char f[256]; + char *dictionary = NULL; + char *password; + const char *reply; + + while ( (c = getopt(argc, argv, "d:cs")) != EOF){ + switch(c) { + case 'd': + dictionary = strdup(optarg); + break; + case 'c': + complex_check = 1; + break; + case 's': + complex_check = 1; + simplex_check = 1; + break; + default: + usage(argv[0]); + } + } + + if (!simplex_check && dictionary == NULL) { + fprintf(stderr, "ERR - Missing cracklib dictionary\n\n"); + usage(argv[0]); + } + + fflush(stdin); + password = fgets(f, sizeof(f), stdin); + + if (password == NULL) { + fprintf(stderr, "ERR - Failed to read password\n\n"); + exit(-2); + } + + if (complex_check) { + ret = complexity(password); + if (ret) { + exit(ret); + } + } + + if (simplex_check) { + exit(0); + } + + reply = FascistCheck(password, dictionary); + if (reply != NULL) { + fprintf(stderr, "ERR - %s\n\n", reply); + exit(-3); + } + + exit(0); +} + diff --git a/examples/autofs/auto.smb b/examples/autofs/auto.smb new file mode 100644 index 0000000..eb24cfa --- /dev/null +++ b/examples/autofs/auto.smb @@ -0,0 +1,11 @@ +# automount points below /smb + +# This is an automounter map and it has the following format +# key [ -mount-options-separated-by-comma ] location +# Details may be found in the autofs(5) manpage + +# smb-servers +supra_andreas -fstype=smb,username=andreas,password=foo ://supra/aheinrich +supra_cspiel -fstype=smb,username=cspiel ://supra/cspiel +phonon_andreas -fstype=smb,username=andreas ://phonon/andreas +helium_cspiel -fstype=smb,username=cspiel ://helium/cspiel diff --git a/examples/dce-dfs/README b/examples/dce-dfs/README new file mode 100644 index 0000000..4aaba8b --- /dev/null +++ b/examples/dce-dfs/README @@ -0,0 +1,4 @@ +this is a sample configuration file from Jim Doyle <doyle@oec.com> who +did the DCE/DFS patches for Samba. It shows how to make DCE/DFS shares +available. + diff --git a/examples/dce-dfs/smb.conf b/examples/dce-dfs/smb.conf new file mode 100644 index 0000000..4221753 --- /dev/null +++ b/examples/dce-dfs/smb.conf @@ -0,0 +1,41 @@ +[global] + printing = bsd + printcap name = /etc/printcap + load printers = no + guest account = guest + log file = /usr/local/samba/var/log.%m + log level = 8 + +[homes] + comment = Home Directories + browsable = no + read only = no + create mode = 0750 + +[test] + comment = test stuff + path = /dept/home/testacct + valid users = testacct + public = no + writable = yes + +[namespace] + comment = DCE-DFS Global Root + path = /... + public = no + writable = yes + +[oecdfs] + comment = Corporate Cell + path = /.../corp.boston.oec.com/fs + browsable = no + read only = no + create mode = 0750 + +[develdfs] + comment = Technology Development Cell + path = /.../devel.boston.oec.com/fs + browsable = no + read only = no + create mode = 0750 + diff --git a/examples/fuse/README b/examples/fuse/README new file mode 100644 index 0000000..a1f311d --- /dev/null +++ b/examples/fuse/README @@ -0,0 +1,7 @@ +WARNING: + +This is experimental work-in-progress code, don't expect it to do +anything sensible. + +Eventually this *might* turn into a fuse client filesystem. This is +not a promise for anything. diff --git a/examples/fuse/clifuse.c b/examples/fuse/clifuse.c new file mode 100644 index 0000000..59af160 --- /dev/null +++ b/examples/fuse/clifuse.c @@ -0,0 +1,1591 @@ +/* + * Unix SMB/CIFS implementation. + * fusermount smb2 client + * Copyright (C) Volker Lendecke 2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define FUSE_USE_VERSION 26 +#define _FILE_OFFSET_BITS 64 +#include "fuse/fuse_lowlevel.h" + +#include "source3/include/includes.h" +#include "client.h" +#include "trans2.h" +#include "libsmb/proto.h" +#include "libsmb/clirap.h" +#include "libsmb/cli_smb2_fnum.h" +#include "lib/util/tevent_ntstatus.h" +#include "libcli/smb/smbXcli_base.h" +#include "libcli/security/security.h" +#include "clifuse.h" +#include "lib/util/idtree.h" + +struct mount_state { + struct tevent_context *ev; + struct cli_state *cli; + bool done; + + struct tevent_fd *fde; + struct tevent_signal *signal_ev; + + struct fuse_chan *ch; + struct fuse_session *se; + + size_t bufsize; + char *buf; + + struct idr_context *ino_ctx; + TALLOC_CTX *ino_parent; +}; + +struct inode_state { + struct idr_context *ino_ctx; + fuse_ino_t ino; + char path[]; +}; + +static int inode_state_destructor(struct inode_state *s); + +static struct inode_state *inode_state_init(TALLOC_CTX *mem_ctx, + struct idr_context *ino_ctx, + const char *path) +{ + struct inode_state *state; + size_t pathlen; + int ino; + + pathlen = strlen(path); + state = talloc_size( + mem_ctx, offsetof(struct inode_state, path) + pathlen + 1); + if (state == NULL) { + return NULL; + } + talloc_set_name_const(state, "struct inode_state"); + + ino = idr_get_new_above(ino_ctx, state, 1, INT32_MAX); + if (ino == -1) { + TALLOC_FREE(state); + return NULL; + } + + state->ino = ino; + state->ino_ctx = ino_ctx; + memcpy(state->path, path, pathlen + 1); + + DBG_DEBUG("Creating ino %d for path %s\n", ino, path); + + talloc_set_destructor(state, inode_state_destructor); + + return state; +} + +static struct inode_state *inode_state_new(struct mount_state *mstate, + const char *path) +{ + return inode_state_init(mstate->ino_parent, mstate->ino_ctx, path); +} + +static int inode_state_destructor(struct inode_state *s) +{ + DBG_DEBUG("destroying inode %ju\n", (uintmax_t)s->ino); + idr_remove(s->ino_ctx, s->ino); + return 0; +} + +struct ll_create_state { + struct mount_state *mstate; + fuse_req_t freq; + struct fuse_file_info fi; + char *path; +}; + +static void cli_ll_create_done(struct tevent_req *req); + +static void cli_ll_create(fuse_req_t freq, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct ll_create_state *state; + struct inode_state *istate; + struct tevent_req *req; + + DBG_DEBUG("parent=%ju, name=%s, mode=%x\n", (uintmax_t)parent, + name, (unsigned)mode); + + istate = idr_find(mstate->ino_ctx, parent); + if (istate == NULL) { + fuse_reply_err(freq, ENOENT); + return; + } + + state = talloc(mstate, struct ll_create_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + state->fi = *fi; + + state->path = talloc_asprintf(state, "%s%s%s", istate->path, + strlen(istate->path) ? "\\": "", + name); + if (state->path == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + + req = cli_smb2_create_fnum_send( + state, + mstate->ev, + mstate->cli, state->path, + (struct cli_smb2_create_flags){0}, + SMB2_IMPERSONATION_IMPERSONATION, + FILE_GENERIC_READ|FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_CREATE, + FILE_NON_DIRECTORY_FILE, + NULL); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_create_done, state); +} + +static void cli_ll_create_done(struct tevent_req *req) +{ + struct ll_create_state *state = tevent_req_callback_data( + req, struct ll_create_state); + struct fuse_entry_param e; + struct inode_state *ino; + uint16_t fnum; + NTSTATUS status; + + status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL, NULL); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + + state->fi.fh = fnum; + state->fi.direct_io = 0; + state->fi.keep_cache = 0; + + ino = inode_state_new(state->mstate, state->path); + if (ino == NULL) { + fuse_reply_err(state->freq, ENOMEM); + return; + } + + e = (struct fuse_entry_param) { + .ino = ino->ino, + .generation = 1, /* FIXME */ + .attr_timeout = 1.0, + .entry_timeout = 1.0 + }; + + fuse_reply_create(state->freq, &e, &state->fi); + + TALLOC_FREE(state); +} + +struct cli_get_unixattr_state { + struct tevent_context *ev; + struct cli_state *cli; + uint64_t fid_persistent; + uint64_t fid_volatile; + + struct timespec create_time; + struct timespec access_time; + struct timespec write_time; + struct timespec change_time; + uint32_t mode; + uint64_t ino; + uint64_t size; +}; + +static void cli_get_unixattr_opened(struct tevent_req *subreq); +static void cli_get_unixattr_gotinfo(struct tevent_req *subreq); +static void cli_get_unixattr_closed(struct tevent_req *subreq); + + +static struct tevent_req *cli_get_unixattr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *path) +{ + struct tevent_req *req, *subreq; + struct cli_get_unixattr_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct cli_get_unixattr_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + + subreq = smb2cli_create_send( + state, ev, cli->conn, cli->timeout, cli->smb2.session, + cli->smb2.tcon, path, SMB2_OPLOCK_LEVEL_NONE, + SMB2_IMPERSONATION_IMPERSONATION, + SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES, 0, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_get_unixattr_opened, req); + + return req; +} + +static void cli_get_unixattr_opened(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_get_unixattr_state *state = tevent_req_data( + req, struct cli_get_unixattr_state); + struct cli_state *cli = state->cli; + NTSTATUS status; + + status = smb2cli_create_recv( + subreq, + &state->fid_persistent, + &state->fid_volatile, + NULL, + NULL, + NULL, + NULL); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + DBG_DEBUG("smb2cli_create_recv returned %s\n", + nt_errstr(status)); + return; + } + + subreq = smb2cli_query_info_send( + state, + state->ev, + cli->conn, + 0, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + FSCC_FILE_ALL_INFORMATION, /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + state->fid_persistent, + state->fid_volatile); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, cli_get_unixattr_gotinfo, req); +} + +static void cli_get_unixattr_gotinfo(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_get_unixattr_state *state = tevent_req_data( + req, struct cli_get_unixattr_state); + struct cli_state *cli = state->cli; + NTSTATUS status; + DATA_BLOB outbuf; + + status = smb2cli_query_info_recv(subreq, state, &outbuf); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + DBG_DEBUG("smb2cli_query_info_recv returned %s\n", + nt_errstr(status)); + return; + } + + if (outbuf.length < 0x60) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + state->create_time = interpret_long_date(BVAL(outbuf.data, 0)); + state->access_time = interpret_long_date(BVAL(outbuf.data, 0x8)); + state->write_time = interpret_long_date(BVAL(outbuf.data, 0x10)); + state->change_time = interpret_long_date(BVAL(outbuf.data, 0x18)); + state->mode = IVAL(outbuf.data, 0x20); + state->size = BVAL(outbuf.data, 0x30); + state->ino = BVAL(outbuf.data, 0x40); + + subreq = smb2cli_close_send(state, state->ev, cli->conn, 0, + cli->smb2.session, cli->smb2.tcon, 0, + state->fid_persistent, + state->fid_volatile); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, cli_get_unixattr_closed, req); +} + +static void cli_get_unixattr_closed(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = smb2cli_close_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + tevent_req_done(req); +} + +static NTSTATUS cli_get_unixattr_recv(struct tevent_req *req, + struct stat *st) +{ + struct cli_get_unixattr_state *state = tevent_req_data( + req, struct cli_get_unixattr_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + + if (state->mode & FILE_ATTRIBUTE_DIRECTORY) { + st->st_mode = (S_IFDIR | 0555); + st->st_nlink = 2; + } else { + st->st_mode = (S_IFREG | 0444); + st->st_nlink = 1; + } + + st->st_size = state->size; + st->st_uid = getuid(); + st->st_gid = getgid(); + st->st_ino = state->ino; + st->st_atime = convert_timespec_to_time_t(state->access_time); + st->st_ctime = convert_timespec_to_time_t(state->change_time); + st->st_mtime = convert_timespec_to_time_t(state->write_time); + + return NT_STATUS_OK; +} + +struct cli_smb2_listdir_state { + struct tevent_context *ev; + struct smbXcli_conn *conn; + uint32_t timeout_msec; + struct smbXcli_session *session; + struct smbXcli_tcon *tcon; + uint8_t level; + uint8_t flags; + uint32_t file_index; + uint64_t fid_persistent; + uint64_t fid_volatile; + const char *mask; + uint32_t outbuf_len; + + uint16_t attribute; + const char *mntpoint; + const char *pathname; + NTSTATUS (*fn)(const char *mntpoint, struct file_info *f, + const char *mask, void *private_data); + void *private_data; + bool processed_file; +}; + +static void cli_smb2_listdir_done(struct tevent_req *subreq); + +static struct tevent_req *cli_smb2_listdir_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbXcli_conn *conn, + uint32_t timeout_msec, + struct smbXcli_session *session, + struct smbXcli_tcon *tcon, + uint8_t level, + uint8_t flags, + uint32_t file_index, + uint64_t fid_persistent, + uint64_t fid_volatile, + const char *mask, + uint32_t outbuf_len, + uint16_t attribute, + const char *mntpoint, + const char *pathname, + NTSTATUS (*fn)(const char *mntpoint, struct file_info *f, + const char *mask, void *private_data), + void *private_data) +{ + struct tevent_req *req, *subreq; + struct cli_smb2_listdir_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct cli_smb2_listdir_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->conn = conn; + state->timeout_msec = timeout_msec; + state->session = session; + state->tcon = tcon; + state->level = level; + state->flags = flags; + state->file_index = file_index; + state->fid_persistent = fid_persistent; + state->fid_volatile = fid_volatile; + state->mask = mask; + state->outbuf_len = outbuf_len; + state->attribute = attribute; + state->mntpoint = mntpoint; + state->pathname = pathname; + state->fn = fn; + state->private_data = private_data; + + subreq = smb2cli_query_directory_send( + state, state->ev, state->conn, state->timeout_msec, + state->session, state->tcon, state->level, + state->flags, state->file_index, + state->fid_persistent, state->fid_volatile, + state->mask, state->outbuf_len); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb2_listdir_done, req); + return req; +} + +static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data, + uint32_t dir_data_length, + struct file_info *finfo, + uint32_t *next_offset) +{ + size_t namelen = 0; + size_t slen = 0; + size_t ret = 0; + + if (dir_data_length < 4) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + *next_offset = IVAL(dir_data, 0); + + if (*next_offset > dir_data_length) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + if (*next_offset != 0) { + /* Ensure we only read what in this record. */ + dir_data_length = *next_offset; + } + + if (dir_data_length < 105) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + finfo->btime_ts = interpret_long_date(BVAL(dir_data, 8)); + finfo->atime_ts = interpret_long_date(BVAL(dir_data, 16)); + finfo->mtime_ts = interpret_long_date(BVAL(dir_data, 24)); + finfo->ctime_ts = interpret_long_date(BVAL(dir_data, 32)); + finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0); + finfo->attr = IVAL(dir_data + 56, 0); + namelen = IVAL(dir_data + 60,0); + if (namelen > (dir_data_length - 104)) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + slen = CVAL(dir_data + 68, 0); + if (slen > 24) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + ret = pull_string_talloc(finfo, + dir_data, + FLAGS2_UNICODE_STRINGS, + &finfo->short_name, + dir_data + 70, + slen, + STR_UNICODE); + if (ret == (size_t)-1) { + /* Bad conversion. */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + ret = pull_string_talloc(finfo, + dir_data, + FLAGS2_UNICODE_STRINGS, + &finfo->name, + dir_data + 104, + namelen, + STR_UNICODE); + if (ret == (size_t)-1) { + /* Bad conversion. */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + return NT_STATUS_OK; +} + +static void cli_smb2_listdir_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_listdir_state *state = tevent_req_data( + req, struct cli_smb2_listdir_state); + uint8_t *data; + uint32_t data_len; + uint32_t next_offset = 0; + NTSTATUS status; + + status = smb2cli_query_directory_recv(subreq, state, &data, + &data_len); + TALLOC_FREE(subreq); + if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) { + tevent_req_done(req); + return; + } + if (tevent_req_nterror(req, status)) { + return; + } + + do { + struct file_info *finfo; + bool ok; + + finfo = talloc_zero(state, struct file_info); + if (tevent_req_nomem(finfo, req)) { + return; + } + + status = parse_finfo_id_both_directory_info( + data, data_len, finfo, &next_offset); + + DEBUG(10, ("%s: parse_finfo_id_both_directory_info returned " + "%s\n", __func__, nt_errstr(status))); + + if (tevent_req_nterror(req, status)) { + return; + } + + ok = dir_check_ftype(finfo->attr, state->attribute); + + DEBUG(10, ("%s: dir_check_ftype(%u,%u) returned %u\n", + __func__, (unsigned)finfo->attr, + (unsigned)state->attribute, (unsigned)ok)); + + if (ok) { + /* + * Only process if attributes match. On SMB1 server + * does this, so on SMB2 we need to emulate in the + * client. + * + * https://bugzilla.samba.org/show_bug.cgi?id=10260 + */ + state->processed_file = true; + + status = state->fn(state->mntpoint, finfo, + state->pathname, + state->private_data); + if (tevent_req_nterror(req, status)) { + return; + } + } + + TALLOC_FREE(finfo); + + if (next_offset != 0) { + data += next_offset; + data_len -= next_offset; + } + } while (next_offset != 0); + + subreq = smb2cli_query_directory_send( + state, state->ev, state->conn, state->timeout_msec, + state->session, state->tcon, state->level, + state->flags, state->file_index, + state->fid_persistent, state->fid_volatile, + state->mask, state->outbuf_len); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, cli_smb2_listdir_done, req); +} + +static NTSTATUS cli_smb2_listdir_recv(struct tevent_req *req) +{ + struct cli_smb2_listdir_state *state = tevent_req_data( + req, struct cli_smb2_listdir_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + + if (!state->processed_file) { + /* + * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE + * if no files match. Emulate this in the client. + */ + return NT_STATUS_NO_SUCH_FILE; + } + + return NT_STATUS_OK; +} + +struct ll_lookup_state { + struct mount_state *mstate; + fuse_req_t freq; + char *path; +}; + +static void cli_ll_lookup_done(struct tevent_req *req); + +static void cli_ll_lookup(fuse_req_t freq, fuse_ino_t parent_ino, + const char *name) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct ll_lookup_state *state; + struct tevent_req *req; + struct inode_state *parent; + + DBG_DEBUG("parent_ino=%ju, name=%s\n", (uintmax_t)parent_ino, name); + + parent = idr_find(mstate->ino_ctx, parent_ino); + if (parent == NULL) { + DBG_WARNING("could not find parent\n"); + fuse_reply_err(freq, ENOENT); + return; + } + + state = talloc(mstate, struct ll_lookup_state); + if (state == NULL) { + DBG_WARNING("talloc failed\n"); + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + + state->path = talloc_asprintf(state, "%s%s%s", parent->path, + strlen(parent->path) ? "\\": "", + name); + if (state->path == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + + req = cli_get_unixattr_send(state, mstate->ev, mstate->cli, + state->path); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_lookup_done, state); +} + +static void cli_ll_lookup_done(struct tevent_req *req) +{ + struct ll_lookup_state *state = tevent_req_callback_data( + req, struct ll_lookup_state); + struct stat sbuf = {0}; + struct fuse_entry_param e; + struct inode_state *ino; + NTSTATUS status; + + status = cli_get_unixattr_recv(req, &sbuf); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + + ino = inode_state_new(state->mstate, state->path); + if (ino == NULL) { + fuse_reply_err(state->freq, ENOMEM); + return; + } + + e = (struct fuse_entry_param) { + .ino = ino->ino, + .attr = sbuf, + .generation = 1, /* FIXME */ + .attr_timeout = 1.0, + .entry_timeout = 1.0 + }; + + fuse_reply_entry(state->freq, &e); + TALLOC_FREE(state); +} + +static void +cli_ll_forget(fuse_req_t freq, fuse_ino_t ino, unsigned long nlookup) +{ + struct mount_state *mstate = + talloc_get_type_abort(fuse_req_userdata(freq), + struct mount_state); + struct inode_state *istate = NULL; + + DBG_DEBUG("ino=%ju, nlookup=%lu\n", (uintmax_t)ino, nlookup); + + istate = idr_find(mstate->ino_ctx, ino); + if (istate == NULL) { + fuse_reply_err(freq, ENOENT); + return; + } + TALLOC_FREE(istate); + fuse_reply_none(freq); +} + +struct ll_getattr_state { + struct mount_state *mstate; + fuse_req_t freq; + struct fuse_file_info fi; +}; + +static void cli_ll_getattr_done(struct tevent_req *req); + +static void cli_ll_getattr(fuse_req_t freq, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct ll_getattr_state *state; + struct inode_state *istate; + struct tevent_req *req; + + DBG_DEBUG("ino=%ju\n", (uintmax_t)ino); + + istate = idr_find(mstate->ino_ctx, ino); + if (istate == NULL) { + fuse_reply_err(freq, ENOENT); + return; + } + + state = talloc(mstate, struct ll_getattr_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + + req = cli_get_unixattr_send(state, mstate->ev, mstate->cli, + istate->path); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_getattr_done, state); +} + +static void cli_ll_getattr_done(struct tevent_req *req) +{ + struct ll_getattr_state *state = tevent_req_callback_data( + req, struct ll_getattr_state); + struct stat st; + NTSTATUS status; + int ret; + + status = cli_get_unixattr_recv(req, &st); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + + ret = fuse_reply_attr(state->freq, &st, 1); + if (ret != 0) { + DBG_NOTICE("fuse_reply_attr failed: %s\n", + strerror(-errno)); + } +} + + +struct ll_open_state { + struct mount_state *mstate; + fuse_req_t freq; + struct fuse_file_info fi; +}; + +static void cli_ll_open_done(struct tevent_req *req); + +static void cli_ll_open(fuse_req_t freq, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct ll_open_state *state; + struct inode_state *istate; + struct tevent_req *req; + uint32_t acc; + + DBG_DEBUG("ino=%ju\n", (uintmax_t)ino); + + istate = idr_find(mstate->ino_ctx, ino); + if (istate == NULL) { + fuse_reply_err(freq, ENOENT); + return; + } + + state = talloc(mstate, struct ll_open_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + state->fi = *fi; + + switch (fi->flags & O_ACCMODE) { + case O_RDONLY: + acc = FILE_GENERIC_READ; + break; + case O_WRONLY: + acc = FILE_GENERIC_WRITE; + break; + case O_RDWR: + acc = FILE_GENERIC_READ|FILE_GENERIC_WRITE; + break; + default: + fuse_reply_err(freq, EACCES); + return; + } + + req = cli_smb2_create_fnum_send( + state, + mstate->ev, + mstate->cli, + istate->path, + (struct cli_smb2_create_flags){0}, + SMB2_IMPERSONATION_IMPERSONATION, + acc, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE, + NULL); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_open_done, state); +} + +static void cli_ll_open_done(struct tevent_req *req) +{ + struct ll_open_state *state = tevent_req_callback_data( + req, struct ll_open_state); + uint16_t fnum; + NTSTATUS status; + + status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL, NULL); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + + state->fi.fh = fnum; + state->fi.direct_io = 0; + state->fi.keep_cache = 0; + + fuse_reply_open(state->freq, &state->fi); + + TALLOC_FREE(state); +} + +struct ll_release_state { + struct mount_state *mstate; + fuse_req_t freq; + fuse_ino_t ino; +}; + +static void cli_ll_release_done(struct tevent_req *req); + +static void cli_ll_release(fuse_req_t freq, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct ll_release_state *state; + struct inode_state *istate; + struct tevent_req *req; + uint16_t fnum; + + DBG_DEBUG("ino=%ju\n", (uintmax_t)ino); + + istate = idr_find(mstate->ino_ctx, ino); + if (istate == NULL) { + fuse_reply_err(freq, ENOENT); + return; + } + + state = talloc(mstate, struct ll_release_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + state->ino = ino; + + fnum = fi->fh; + + req = cli_smb2_close_fnum_send(state, mstate->ev, mstate->cli, fnum, 0); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_release_done, state); +} + +static void cli_ll_release_done(struct tevent_req *req) +{ + struct ll_release_state *state = tevent_req_callback_data( + req, struct ll_release_state); + struct inode_state *istate; + NTSTATUS status; + + status = cli_smb2_close_fnum_recv(req); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + + istate = idr_find(state->mstate->ino_ctx, state->ino); + if (istate == NULL) { + DEBUG(1, ("%s: inode %ju vanished!\n", __func__, + (uintmax_t)state->ino)); + } + TALLOC_FREE(istate); + + fuse_reply_err(state->freq, 0); + TALLOC_FREE(state); +} + +struct ll_read_state { + struct mount_state *mstate; + fuse_req_t freq; +}; + +static void cli_ll_read_done(struct tevent_req *req); + +static void cli_ll_read(fuse_req_t freq, fuse_ino_t ino, + size_t size, off_t off, + struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct ll_read_state *state; + struct tevent_req *req; + uint16_t fnum; + + DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino, + size, (uintmax_t)off); + + state = talloc(mstate, struct ll_read_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + + fnum = fi->fh; + + req = cli_smb2_read_send(state, mstate->ev, mstate->cli, + fnum, off, size); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_read_done, state); +} + +static void cli_ll_read_done(struct tevent_req *req) +{ + struct ll_read_state *state = tevent_req_callback_data( + req, struct ll_read_state); + ssize_t received; + uint8_t *rcvbuf; + NTSTATUS status; + + status = cli_smb2_read_recv(req, &received, &rcvbuf); + /* no talloc_free here yet */ + + if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { + received = 0; + rcvbuf = NULL; + status = NT_STATUS_OK; + } + + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + fuse_reply_buf(state->freq, (char *)rcvbuf, received); + TALLOC_FREE(state); +} + +struct ll_write_state { + struct mount_state *mstate; + fuse_req_t freq; +}; + +static void cli_ll_write_done(struct tevent_req *req); + +static void cli_ll_write(fuse_req_t freq, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct ll_write_state *state; + struct tevent_req *req; + uint16_t fnum; + + DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino, + size, (uintmax_t)off); + + state = talloc(mstate, struct ll_write_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + + fnum = fi->fh; + + req = cli_smb2_write_send(state, mstate->ev, mstate->cli, fnum, 0, + (const uint8_t *)buf, off, size); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_write_done, state); +} + +static void cli_ll_write_done(struct tevent_req *req) +{ + struct ll_write_state *state = tevent_req_callback_data( + req, struct ll_write_state); + size_t written; + NTSTATUS status; + + status = cli_smb2_write_recv(req, &written); + /* no talloc_free here yet */ + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + fuse_reply_write(state->freq, written); + TALLOC_FREE(state); +} + + +struct ll_dir_state { + uint64_t fid_persistent; + uint64_t fid_volatile; + + struct file_info *finfos; + unsigned num_finfos, num_sent; +}; + +static bool ll_dir_state_add(struct ll_dir_state *dir_state, + const char *name) +{ + struct file_info *tmp, *finfo; + + tmp = talloc_realloc(dir_state, dir_state->finfos, + struct file_info, dir_state->num_finfos+1); + if (tmp == NULL) { + return false; + } + dir_state->finfos = tmp; + finfo = &dir_state->finfos[dir_state->num_finfos]; + + ZERO_STRUCTP(finfo); + + finfo->name = talloc_strdup(dir_state->finfos, name); + if (finfo->name == NULL) { + return false; + } + dir_state->num_finfos += 1; + + return true; +} + +struct ll_opendir_state { + struct mount_state *mstate; + fuse_req_t freq; + struct fuse_file_info fi; + struct ll_dir_state *dir_state; +}; + +static void cli_ll_opendir_done(struct tevent_req *req); + +static void cli_ll_opendir(fuse_req_t freq, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct cli_state *cli = mstate->cli; + struct ll_opendir_state *state; + struct inode_state *istate; + struct tevent_req *req; + + DBG_DEBUG("ino=%ju\n", (uintmax_t)ino); + + istate = idr_find(mstate->ino_ctx, ino); + if (istate == NULL) { + fuse_reply_err(freq, ENOENT); + return; + } + + state = talloc(mstate, struct ll_opendir_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + state->fi = *fi; + + state->dir_state = talloc_zero(state, struct ll_dir_state); + if (state->dir_state == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + + req = smb2cli_create_send( + state, mstate->ev, cli->conn, cli->timeout, + cli->smb2.session, cli->smb2.tcon, istate->path, + 0, SMB2_IMPERSONATION_IMPERSONATION, + FILE_GENERIC_READ, FILE_ATTRIBUTE_DIRECTORY, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, FILE_DIRECTORY_FILE, NULL); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_opendir_done, state); +} + +static void cli_ll_opendir_done(struct tevent_req *req) +{ + struct ll_opendir_state *state = tevent_req_callback_data( + req, struct ll_opendir_state); + NTSTATUS status; + + status = smb2cli_create_recv( + req, + &state->dir_state->fid_persistent, + &state->dir_state->fid_volatile, + NULL, + NULL, + NULL, + NULL); + TALLOC_FREE(req); + + DEBUG(10, ("%s: smbcli_create_recv returned %s\n", __func__, + nt_errstr(status))); + + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + + state->fi.fh = (uint64_t)talloc_move(state->mstate, &state->dir_state); + state->fi.direct_io = 0; + state->fi.keep_cache = 0; + + fuse_reply_open(state->freq, &state->fi); + + TALLOC_FREE(state); +} + +struct ll_readdir_state { + fuse_req_t freq; + struct ll_dir_state *dir_state; +}; + +static void cli_ll_readdir_done(struct tevent_req *subreq); +static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo, + const char *path, void *private_data); +static void cli_ll_readdir_reply_one(fuse_req_t freq, + struct ll_dir_state *dir_state); + +static void cli_ll_readdir(fuse_req_t freq, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct cli_state *cli = mstate->cli; + struct ll_dir_state *dir_state; + struct ll_readdir_state *state; + struct tevent_req *req; + + DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino, size, + (uintmax_t)off); + + dir_state = talloc_get_type_abort((void *)fi->fh, struct ll_dir_state); + + if (dir_state->finfos != NULL) { + DBG_DEBUG("finfos=%p\n", dir_state->finfos); + cli_ll_readdir_reply_one(freq, dir_state); + return; + } + + if (!ll_dir_state_add(dir_state, ".") || + !ll_dir_state_add(dir_state, "..")) { + fuse_reply_err(freq, ENOMEM); + return; + } + + state = talloc(mstate, struct ll_readdir_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->freq = freq; + state->dir_state = dir_state; + + req = cli_smb2_listdir_send( + state, mstate->ev, cli->conn, cli->timeout, + cli->smb2.session, cli->smb2.tcon, + SMB2_FIND_ID_BOTH_DIRECTORY_INFO, 0, 0, + dir_state->fid_persistent, dir_state->fid_volatile, + "*", 0xffff, + FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN, + NULL, NULL, cli_ll_readdir_one, dir_state); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_readdir_done, state); +} + +static void cli_ll_readdir_reply_one(fuse_req_t freq, + struct ll_dir_state *dir_state) +{ + struct file_info *finfo; + char buf[1024]; + struct stat sbuf = {}; + size_t buflen; + + if (dir_state->num_finfos == dir_state->num_sent) { + DEBUG(10, ("%s: Done\n", __func__)); + fuse_reply_buf(freq, NULL, 0); + return; + } + + sbuf.st_mode = S_IFREG | 0755; + sbuf.st_ino = random(); /* FIXME :-) */ + finfo = &dir_state->finfos[dir_state->num_sent]; + + DBG_DEBUG("Adding %s\n", finfo->name); + + buflen = fuse_add_direntry(freq, buf, sizeof(buf), + finfo->name, &sbuf, 0); + fuse_reply_buf(freq, buf, buflen); + dir_state->num_sent += 1; + return; +} + +static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo, + const char *path, void *private_data) +{ + struct ll_dir_state *dir_state = talloc_get_type_abort( + private_data, struct ll_dir_state); + + if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) { + DEBUG(10, ("%s: Ignoring %s\n", __func__, finfo->name)); + return NT_STATUS_OK; + } + + DBG_DEBUG("Got entry %s\n", finfo->name); + + if (!ll_dir_state_add(dir_state, finfo->name)) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; +} + +static void cli_ll_readdir_done(struct tevent_req *req) +{ + struct ll_readdir_state *state = tevent_req_callback_data( + req, struct ll_readdir_state); + NTSTATUS status; + + status = cli_smb2_listdir_recv(req); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + cli_ll_readdir_reply_one(state->freq, state->dir_state); + TALLOC_FREE(state); +} + + +struct ll_releasedir_state { + struct mount_state *mstate; + fuse_req_t freq; + struct ll_dir_state *dir_state; +}; + +static void cli_ll_releasedir_done(struct tevent_req *req); + +static void cli_ll_releasedir(fuse_req_t freq, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct mount_state *mstate = talloc_get_type_abort( + fuse_req_userdata(freq), struct mount_state); + struct cli_state *cli = mstate->cli; + struct ll_releasedir_state *state; + struct tevent_req *req; + + DBG_DEBUG("ino=%ju\n", (uintmax_t)ino); + + state = talloc(mstate, struct ll_releasedir_state); + if (state == NULL) { + fuse_reply_err(freq, ENOMEM); + return; + } + state->mstate = mstate; + state->freq = freq; + + state->dir_state = talloc_get_type_abort( + (void *)fi->fh, struct ll_dir_state); + + req = smb2cli_close_send(state, mstate->ev, cli->conn, cli->timeout, + cli->smb2.session, cli->smb2.tcon, 0, + state->dir_state->fid_persistent, + state->dir_state->fid_volatile); + if (req == NULL) { + TALLOC_FREE(state); + fuse_reply_err(freq, ENOMEM); + return; + } + tevent_req_set_callback(req, cli_ll_releasedir_done, state); +} + +static void cli_ll_releasedir_done(struct tevent_req *req) +{ + struct ll_releasedir_state *state = tevent_req_callback_data( + req, struct ll_releasedir_state); + NTSTATUS status; + + status = smb2cli_close_recv(req); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + fuse_reply_err(state->freq, map_errno_from_nt_status(status)); + return; + } + TALLOC_FREE(state->dir_state); + fuse_reply_err(state->freq, 0); + TALLOC_FREE(state); +} + +static struct fuse_lowlevel_ops cli_ll_ops = { + .lookup = cli_ll_lookup, + .forget = cli_ll_forget, + .getattr = cli_ll_getattr, + .open = cli_ll_open, + .create = cli_ll_create, + .release = cli_ll_release, + .read = cli_ll_read, + .write = cli_ll_write, + .opendir = cli_ll_opendir, + .readdir = cli_ll_readdir, + .releasedir = cli_ll_releasedir, +}; + +static void fuse_chan_fd_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, + void *private_data); +static void fuse_chan_signal_handler(struct tevent_context *ev, + struct tevent_signal *se, + int signum, + int count, + void *siginfo, + void *private_data); + +static int mount_state_destructor(struct mount_state *s); + +int do_mount(struct cli_state *cli, const char *mountpoint) +{ + struct mount_state *state; + struct inode_state *ino; + struct fuse_args args = { 0 }; + int fd; + int ret = 1; + + state = talloc_zero(talloc_tos(), struct mount_state); + if (state == NULL) { + fprintf(stderr, "talloc failed\n"); + return 1; + } + + state->ev = tevent_context_init(state); + if (state->ev == NULL) { + fprintf(stderr, "tevent_context_init failed\n"); + TALLOC_FREE(state); + return 1; + } + + state->ino_ctx = idr_init(state); + if (state->ino_ctx == NULL) { + fprintf(stderr, "idr_init failed\n"); + TALLOC_FREE(state); + return 1; + } + + state->ino_parent = talloc_new(state); + if (state->ino_parent == NULL) { + fprintf(stderr, "talloc_new failed\n"); + TALLOC_FREE(state); + return 1; + } + + talloc_set_destructor(state, mount_state_destructor); + + ino = inode_state_new(state, ""); + if (ino == NULL) { + fprintf(stderr, "inode_state_new failed\n"); + TALLOC_FREE(state); + return 1; + } + if (ino->ino != FUSE_ROOT_ID) { + fprintf(stderr, "first inode gave %d, expected %d\n", + (int)ino->ino, FUSE_ROOT_ID); + TALLOC_FREE(state); + return 1; + } + + state->cli = cli; + + state->ch = fuse_mount(mountpoint, &args); + if (state->ch == NULL) { + perror("fuse_mount failed"); + goto fail_free; + } + + state->bufsize = fuse_chan_bufsize(state->ch); + state->buf = talloc_array(state, char, state->bufsize); + if (state->buf == NULL) { + fprintf(stderr, "talloc failed\n"); + goto fail_unmount; + } + + fd = fuse_chan_fd(state->ch); + + state->fde = tevent_add_fd(state->ev, state, fd, TEVENT_FD_READ, + fuse_chan_fd_handler, state); + if (state->fde == NULL) { + fprintf(stderr, "tevent_add_fd failed\n"); + goto fail_unmount; + } + + state->signal_ev = tevent_add_signal(state->ev, state, SIGINT, 0, + fuse_chan_signal_handler, state); + if (state->signal_ev == NULL) { + fprintf(stderr, "tevent_add_signal failed\n"); + goto fail_unmount; + } + + state->se = fuse_lowlevel_new(&args, &cli_ll_ops, sizeof(cli_ll_ops), + state); + if (state->se == NULL) { + perror("fuse_lowlevel_new failed"); + goto fail_unmount; + } + + fuse_session_add_chan(state->se, state->ch); + + while (!state->done) { + ret = tevent_loop_once(state->ev); + if (ret == -1) { + perror("tevent_loop_once failed"); + break; + } + } + + fuse_session_remove_chan(state->ch); + fuse_session_destroy(state->se); +fail_unmount: + fuse_unmount(mountpoint, state->ch); +fail_free: + TALLOC_FREE(state); + return ret; +} + +static int mount_state_destructor(struct mount_state *s) +{ + TALLOC_FREE(s->ino_parent); + return 0; +} + + +static void fuse_chan_fd_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, + void *private_data) +{ + struct mount_state *state = talloc_get_type_abort( + private_data, struct mount_state); + int recvd; + + if ((flags & TEVENT_FD_READ) == 0) { + return; + } + + recvd = fuse_chan_recv(&state->ch, state->buf, state->bufsize); + if (recvd <= 0) { + state->done = true; + return; + } + fuse_session_process(state->se, state->buf, recvd, state->ch); +} + +static void fuse_chan_signal_handler(struct tevent_context *ev, + struct tevent_signal *se, + int signum, + int count, + void *siginfo, + void *private_data) +{ + struct mount_state *state = talloc_get_type_abort( + private_data, struct mount_state); + state->done = true; +} diff --git a/examples/fuse/clifuse.h b/examples/fuse/clifuse.h new file mode 100644 index 0000000..62a2666 --- /dev/null +++ b/examples/fuse/clifuse.h @@ -0,0 +1,27 @@ +/* + * Unix SMB/CIFS implementation. + * fusermount smb2 client + * Copyright (C) Volker Lendecke 2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __EXAMPLES_FUSE_CLIFUSE_H__ +#define __EXAMPLES_FUSE_CLIFUSE_H__ + +struct cli_state; + +int do_mount(struct cli_state *cli, const char *mountpoint); + +#endif diff --git a/examples/fuse/smb2mount.c b/examples/fuse/smb2mount.c new file mode 100644 index 0000000..0594ced --- /dev/null +++ b/examples/fuse/smb2mount.c @@ -0,0 +1,160 @@ +/* + * Unix SMB/CIFS implementation. + * fusermount smb2 client + * + * Copyright (C) Volker Lendecke 2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "source3/include/includes.h" +#include "popt.h" +#include "lib/cmdline/cmdline.h" +#include "lib/param/param.h" +#include "client.h" +#include "libsmb/proto.h" +#include "clifuse.h" + +static struct cli_state *connect_one(struct cli_credentials *creds, + const char *server, int port, + const char *share) +{ + struct cli_state *c = NULL; + NTSTATUS nt_status; + uint32_t flags = 0; + + nt_status = cli_full_connection_creds(&c, lp_netbios_name(), server, + NULL, port, + share, "?????", + creds, + flags); + if (!NT_STATUS_IS_OK(nt_status)) { + DBG_ERR("cli_full_connection failed! (%s)\n", + nt_errstr(nt_status)); + return NULL; + } + + return c; +} + +int main(int argc, char *argv[]) +{ + const char **argv_const = discard_const_p(const char *, argv); + TALLOC_CTX *frame = talloc_stackframe(); + struct loadparm_context *lp_ctx = NULL; + poptContext pc; + int opt, ret; + int port = 0; + char *unc, *mountpoint, *server, *share; + struct cli_state *cli; + struct cli_credentials *creds = NULL; + bool ok; + + struct poptOption long_options[] = { + POPT_AUTOHELP + POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS + { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", + "PORT" }, + POPT_TABLEEND + }; + + smb_init_locale(); + + ok = samba_cmdline_init(frame, + SAMBA_CMDLINE_CONFIG_CLIENT, + false /* require_smbconf */); + if (!ok) { + DBG_ERR("Failed to init cmdline parser!\n"); + TALLOC_FREE(frame); + exit(1); + } + lp_ctx = samba_cmdline_get_lp_ctx(); + lpcfg_set_cmdline(lp_ctx, "client min protocol", "SMB2"); + lpcfg_set_cmdline(lp_ctx, "client max protocol", "SMB3_11"); + + pc = samba_popt_get_context(getprogname(), + argc, + argv_const, + long_options, + 0); + if (pc == NULL) { + DBG_ERR("Failed to setup popt context!\n"); + TALLOC_FREE(frame); + exit(1); + } + + poptSetOtherOptionHelp(pc, "//server1/share1 mountpoint"); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + case 'p': + break; + default: + fprintf(stderr, "Unknown Option: %c\n", opt); + exit(1); + } + } + + if (!poptPeekArg(pc)) { + poptPrintUsage(pc, stderr, 0); + return -1; + } + unc = talloc_strdup(frame, poptGetArg(pc)); + if (unc == NULL) { + return -1; + } + string_replace(unc,'/','\\'); + + if (!poptPeekArg(pc)) { + poptPrintUsage(pc, stderr, 0); + return -1; + } + mountpoint = talloc_strdup(frame, poptGetArg(pc)); + if (mountpoint == NULL) { + return -1; + } + + poptFreeContext(pc); + samba_cmdline_burn(argc, argv); + + server = talloc_strdup(frame, unc+2); + if (!server) { + return -1; + } + share = strchr_m(server,'\\'); + if (!share) { + fprintf(stderr, "Invalid argument: %s\n", server); + return -1; + } + + *share = 0; + share++; + + creds = samba_cmdline_get_creds(); + + cli = connect_one(creds, server, port, share); + if (cli == NULL) { + return -1; + } + + ret = do_mount(cli, mountpoint); + if (ret != 0) { + fprintf(stderr, "mount failed\n"); + return -1; + } + + TALLOC_FREE(frame); + return 0; +} diff --git a/examples/fuse/wscript b/examples/fuse/wscript new file mode 100644 index 0000000..1c85139 --- /dev/null +++ b/examples/fuse/wscript @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +def configure(conf): + # Check for fuse support + if conf.CHECK_CODE(''' + #define FUSE_USE_VERSION 26 + #define _FILE_OFFSET_BITS 64 + #include "fuse/fuse_lowlevel.h" + int main(void) { return 0; } + ''', 'HAVE_FUSE_FUSE_LOWLEVEL_H', + addmain=False, + execute=False) and conf.CHECK_FUNCS_IN('fuse_mount', + 'fuse'): + conf.DEFINE('HAVE_FUSE', 1) diff --git a/examples/fuse/wscript_build b/examples/fuse/wscript_build new file mode 100644 index 0000000..ceef925 --- /dev/null +++ b/examples/fuse/wscript_build @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +if bld.env.HAVE_FUSE: + bld.SAMBA_BINARY('smb2mount', + source='smb2mount.c clifuse.c', + deps='smbconf CMDLINE_S3 libsmb fuse', + install=False) diff --git a/examples/libsmbclient/Makefile b/examples/libsmbclient/Makefile new file mode 100644 index 0000000..08ff19a --- /dev/null +++ b/examples/libsmbclient/Makefile @@ -0,0 +1,116 @@ +# +CC = gcc + +SAMBA_INCL = -I/usr/local/samba/include +EXTLIB_INCL = -I/usr/include/gtk-1.2 \ + -I/usr/include/glib-1.2 \ + -I/usr/lib/glib/include +EXTLIB_INCL = `gtk-config --cflags` + +DEFS = -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE +CFLAGS = -O0 -g $(SAMBA_INCL) $(EXTLIB_INCL) $(DEFS) + +LDFLAGS = -L/usr/local/samba/lib \ + -lldap -lkrb5 -lgssapi_krb5 +#LIBSMBCLIENT = /usr/local/samba/lib/libsmbclient.so +LIBSMBCLIENT = -lwbclient -lsmbclient -ltalloc -ltdb -ldl -lresolv + +TESTS= testsmbc \ + testacl \ + testacl2 \ + testacl3 \ + testbrowse \ + testbrowse2 \ + teststat \ + teststat2 \ + teststat3 \ + teststatvfs \ + testfstatvfs \ + testtruncate \ + testchmod \ + testutime \ + testread \ + testwrite + +# tree \ + +all: $(TESTS) smbsh + +testsmbc: testsmbc.o + @echo Linking testsmbc + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) + +tree: tree.o + @echo Linking tree + $(CC) `gtk-config --cflags` $(CFLAGS) $(LDFLAGS) -o $@ $< `gtk-config --libs` $(LIBSMBCLIENT) + +testacl: testacl.o + @echo Linking testacl + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testacl2: testacl2.o + @echo Linking testacl2 + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testacl3: testacl3.o + @echo Linking testacl3 + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testbrowse: testbrowse.o + @echo Linking testbrowse + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testbrowse2: testbrowse2.o + @echo Linking testbrowse2 + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +teststat: teststat.o + @echo Linking teststat + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +teststat2: teststat2.o + @echo Linking teststat2 + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +teststat3: teststat3.o + @echo Linking teststat3 + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +teststatvfs: teststatvfs.o + @echo Linking teststatvfs + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testfstatvfs: testfstatvfs.o + @echo Linking testfstatvfs + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testtruncate: testtruncate.o + @echo Linking testtruncate + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testchmod: testchmod.o + @echo Linking testchmod + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testutime: testutime.o + @echo Linking testutime + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testread: testread.o + @echo Linking testread + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testwrite: testwrite.o + @echo Linking testwrite + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testctx: testctx.o + @echo Linking testctx + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +smbsh: + make -C smbwrapper + +clean: + @rm -f *.o *~ $(TESTS) + @make -C smbwrapper clean diff --git a/examples/libsmbclient/Makefile.internal.in b/examples/libsmbclient/Makefile.internal.in new file mode 100644 index 0000000..d9f0fd3 --- /dev/null +++ b/examples/libsmbclient/Makefile.internal.in @@ -0,0 +1,138 @@ +# Makefile.internal.in for building the libsmbclient examples +# from within a samba build. +# +# Use Makfile for building the examples with a libsmbclient +# installed to /usr/local/samba + +CC = @CC@ + +SAMBA_DIR = ../../source3 +SAMBA_INCLUDES = -I$(SAMBA_DIR)/include +SAMBA_LIBPATH = -L$(SAMBA_DIR)/bin + +GTK_CFLAGS = `gtk-config --cflags` +GTK_LIBS = `gtk-config --libs` + +#GTK_CFLAGS = `pkg-config gtk+-2.0 --cflags` +#GTK_LIBS = `pkg-config gtk+-2.0 --libs` + +CCFLAGS = @CPPFLAGS@ @CFLAGS@ $(GTK_CFLAGS) $(SAMBA_INCLUDES) + +PICFLAG=@PICFLAG@ +LDFLAGS= $(SAMBA_LIBPATH) @PIE_LDFLAGS@ @LDFLAGS@ + +EXTERNAL_LIBS = @LIBS@ @LDAP_LIBS@ @KRB5_LIBS@ @NSCD_LIBS@ +LIBSMBCLIENT_LIBS = -lwbclient -lsmbclient -ltalloc -ltdb -ldl -lresolv +CMDLINE_LIBS = @POPTLIBS@ +LIBS = $(EXTERNAL_LIBS) $(LIBSMBCLIENT_LIBS) + +# Compile a source file. (.c --> .o) +COMPILE_CC = $(CC) -I. $(CCFLAGS) $(PICFLAG) -c $< -o $@ +COMPILE = $(COMPILE_CC) + +MAKEDIR = || exec false; \ + if test -d "$$dir"; then :; else \ + echo mkdir "$$dir"; \ + mkdir -p "$$dir" >/dev/null 2>&1 || \ + test -d "$$dir" || \ + mkdir "$$dir" || \ + exec false; fi || exec false + +TESTS= testsmbc \ + testacl \ + testacl2 \ + testacl3 \ + testbrowse \ + testbrowse2 \ + teststat \ + teststat2 \ + teststat3 \ + testtruncate \ + testchmod \ + testutime \ + testread \ + testwrite + +# tree \ + +all: $(TESTS) smbsh + +.c.o: + @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \ + dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi + @echo Compiling $*.c + @$(COMPILE) && exit 0;\ + echo "The following command failed:" 1>&2;\ + echo "$(COMPILE_CC)" 1>&2;\ + $(COMPILE_CC) >/dev/null 2>&1 + +testsmbc: testsmbc.o + @echo Linking testsmbc + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) + +tree: tree.o + @echo Linking tree + @$(CC) $(GTK_CFLAGS) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(GTK_LIBS) $(LIBS) + +testacl: testacl.o + @echo Linking testacl + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testacl2: testacl2.o + @echo Linking testacl2 + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testacl3: testacl3.o + @echo Linking testacl3 + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testbrowse: testbrowse.o + @echo Linking testbrowse + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testbrowse2: testbrowse2.o + @echo Linking testbrowse2 + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +teststat: teststat.o + @echo Linking teststat + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +teststat2: teststat2.o + @echo Linking teststat2 + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +teststat3: teststat3.o + @echo Linking teststat3 + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testtruncate: testtruncate.o + @echo Linking testtruncate + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testchmod: testchmod.o + @echo Linking testchmod + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testutime: testutime.o + @echo Linking testutime + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testread: testread.o + @echo Linking testread + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testwrite: testwrite.o + @echo Linking testwrite + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +testctx: testctx.o + @echo Linking testctx + @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS) + +smbsh: + make -C smbwrapper + +clean: + @rm -f *.o *~ $(TESTS) + @make -C smbwrapper clean diff --git a/examples/libsmbclient/README b/examples/libsmbclient/README new file mode 100644 index 0000000..c45dd8b --- /dev/null +++ b/examples/libsmbclient/README @@ -0,0 +1,17 @@ +Some simple example programs for libsmbclient ... + +testsmbc.c is kinda broken as it has many hardcoded bits in it + +testbrowse.c opens a remote folder and displays its contents + +teststat.c allows comparing the results of smbc_stat() against a local stat() of +the same file. + +tree.c is an example of how you might do some of these things with GTK+ +It needs lots of work but shows you some ways to use libsmbclient. + +smbwrapper implements the old smbsh/smbwrapper mechanism using libsmbclient, in +such a way that it works on Linux + +Richard Sharpe, 17 May 2001 +Derrell Lipman, 30 Mar 2005 diff --git a/examples/libsmbclient/get_auth_data_fn.h b/examples/libsmbclient/get_auth_data_fn.h new file mode 100644 index 0000000..9adb745 --- /dev/null +++ b/examples/libsmbclient/get_auth_data_fn.h @@ -0,0 +1,92 @@ +#include <stdlib.h> + +static void +get_auth_data_fn(const char * pServer, + const char * pShare, + char * pWorkgroup, + int maxLenWorkgroup, + char * pUsername, + int maxLenUsername, + char * pPassword, + int maxLenPassword) +{ + char temp[128]; + char server[256] = { '\0' }; + char share[256] = { '\0' }; + char workgroup[256] = { '\0' }; + char username[256] = { '\0' }; + char password[256] = { '\0' }; + char *ret; + + static int krb5_set = 1; + + if (strcmp(server, pServer) == 0 && + strcmp(share, pShare) == 0 && + *workgroup != '\0' && + *username != '\0') + { + strncpy(pWorkgroup, workgroup, maxLenWorkgroup - 1); + strncpy(pUsername, username, maxLenUsername - 1); + strncpy(pPassword, password, maxLenPassword - 1); + return; + } + + if (krb5_set && getenv("KRB5CCNAME")) { + krb5_set = 0; + return; + } + + fprintf(stdout, "Workgroup: [%s] ", pWorkgroup); + ret = fgets(temp, sizeof(temp), stdin); + if (ret == NULL) { + return; + } + + if (temp[strlen(temp) - 1] == '\n') /* A new line? */ + { + temp[strlen(temp) - 1] = '\0'; + } + + if (temp[0] != '\0') + { + strncpy(pWorkgroup, temp, maxLenWorkgroup - 1); + } + + fprintf(stdout, "Username: [%s] ", pUsername); + ret = fgets(temp, sizeof(temp), stdin); + if (ret == NULL) { + return; + } + + if (temp[strlen(temp) - 1] == '\n') /* A new line? */ + { + temp[strlen(temp) - 1] = '\0'; + } + + if (temp[0] != '\0') + { + strncpy(pUsername, temp, maxLenUsername - 1); + } + + fprintf(stdout, "Password: "); + ret = fgets(temp, sizeof(temp), stdin); + if (ret == NULL) { + return; + } + + if (temp[strlen(temp) - 1] == '\n') /* A new line? */ + { + temp[strlen(temp) - 1] = '\0'; + } + + if (temp[0] != '\0') + { + strncpy(pPassword, temp, maxLenPassword - 1); + } + + strncpy(workgroup, pWorkgroup, sizeof(workgroup) - 1); + strncpy(username, pUsername, sizeof(username) - 1); + strncpy(password, pPassword, sizeof(password) - 1); + + krb5_set = 1; +} diff --git a/examples/libsmbclient/testacl.c b/examples/libsmbclient/testacl.c new file mode 100644 index 0000000..e0e4eeb --- /dev/null +++ b/examples/libsmbclient/testacl.c @@ -0,0 +1,333 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <popt.h> +#include "libsmbclient.h" +#include "get_auth_data_fn.h" + +enum acl_mode +{ + SMB_ACL_LIST, + SMB_ACL_GET, + SMB_ACL_SET, + SMB_ACL_DELETE, + SMB_ACL_MODIFY, + SMB_ACL_ADD, + SMB_ACL_CHOWN, + SMB_ACL_CHGRP +}; + + +int main(int argc, const char *argv[]) +{ + int opt; + int flags = 0; + int debug = 0; + int numeric = 0; + int stat_and_retry = 0; + int full_time_names = 0; + enum acl_mode mode = SMB_ACL_LIST; + static const char *the_acl = NULL; + int ret; + char *p; + const char *debugstr; + char path[1024]; + char value[1024]; + poptContext pc; + struct stat st; + struct poptOption long_options[] = + { + POPT_AUTOHELP + { + .longName = "numeric", + .shortName = 'n', + .argInfo = POPT_ARG_NONE, + .arg = &numeric, + .val = 1, + .descrip = "Don't resolve sids or masks to names" + }, + { + .longName = "debug", + .shortName = 'd', + .argInfo = POPT_ARG_INT, + .arg = &debug, + .val = 0, + .descrip = "Set debug level (0-100)" + }, + { + .longName = "full_time_names", + .shortName = 'f', + .argInfo = POPT_ARG_NONE, + .arg = &full_time_names, + .val = 1, + .descrip = "Use new style xattr names, which include CREATE_TIME" + }, + { + .longName = "delete", + .shortName = 'D', + .argInfo = POPT_ARG_STRING, + .arg = NULL, + .val = 'D', + .descrip = "Delete an acl", + .argDescrip = "ACL" + }, + { + .longName = "modify", + .shortName = 'M', + .argInfo = POPT_ARG_STRING, + .arg = NULL, + .val = 'M', + .descrip = "Modify an acl", + .argDescrip = "ACL" + }, + { + .longName = "add", + .shortName = 'a', + .argInfo = POPT_ARG_STRING, + .arg = NULL, + .val = 'a', + .descrip = "Add an acl", + .argDescrip = "ACL" + }, + { + .longName = "set", + .shortName = 'S', + .argInfo = POPT_ARG_STRING, + .arg = NULL, + .val = 'S', + .descrip = "Set acls", + .argDescrip = "ACLS" + }, + { + .longName = "chown", + .shortName = 'C', + .argInfo = POPT_ARG_STRING, + .arg = NULL, + .val = 'C', + .descrip = "Change ownership of a file", + .argDescrip = "USERNAME" + }, + { + .longName = "chgrp", + .shortName = 'G', + .argInfo = POPT_ARG_STRING, + .arg = NULL, + .val = 'G', + .descrip = "Change group ownership of a file", + .argDescrip = "GROUPNAME" + }, + { + .longName = "get", + .shortName = 'g', + .argInfo = POPT_ARG_STRING, + .arg = NULL, + .val = 'g', + .descrip = "Get a specific acl attribute", + .argDescrip = "ACL" + }, + { + .longName = "stat_and_retry", + .shortName = 'R', + .argInfo = POPT_ARG_NONE, + .arg = &stat_and_retry, + .val = 1, + .descrip = "After 'get' do 'stat' and another 'get'" + }, + POPT_TABLEEND + }; + + setbuf(stdout, NULL); + + pc = poptGetContext("smbcacls", argc, argv, long_options, 0); + + poptSetOtherOptionHelp(pc, "smb://server1/share1/filename"); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case 'S': + the_acl = strdup(poptGetOptArg(pc)); + mode = SMB_ACL_SET; + break; + + case 'D': + the_acl = strdup(poptGetOptArg(pc)); + mode = SMB_ACL_DELETE; + break; + + case 'M': + the_acl = strdup(poptGetOptArg(pc)); + mode = SMB_ACL_MODIFY; + break; + + case 'a': + the_acl = strdup(poptGetOptArg(pc)); + mode = SMB_ACL_ADD; + break; + + case 'g': + the_acl = strdup(poptGetOptArg(pc)); + mode = SMB_ACL_GET; + break; + + case 'C': + the_acl = strdup(poptGetOptArg(pc)); + mode = SMB_ACL_CHOWN; + break; + + case 'G': + the_acl = strdup(poptGetOptArg(pc)); + mode = SMB_ACL_CHGRP; + break; + } + } + + /* Make connection to server */ + if(!poptPeekArg(pc)) { + poptPrintUsage(pc, stderr, 0); + return 1; + } + + strncpy(path, poptGetArg(pc), sizeof(path)); + path[sizeof(path)-1] = '\0'; + + if (smbc_init(get_auth_data_fn, debug) != 0) + { + printf("Could not initialize smbc_ library\n"); + return 1; + } + + if (full_time_names) { + SMBCCTX *context = smbc_set_context(NULL); + smbc_setOptionFullTimeNames(context, 1); + } + + /* Perform requested action */ + + switch(mode) + { + case SMB_ACL_LIST: + ret = smbc_listxattr(path, value, sizeof(value)-2); + if (ret < 0) + { + printf("Could not get attribute list for [%s] %d: %s\n", + path, errno, strerror(errno)); + return 1; + } + + /* + * The list of attributes has a series of null-terminated strings. + * The list of strings terminates with an extra null byte, thus two in + * a row. Ensure that our buffer, which is conceivably shorter than + * the list of attributes, actually ends with two null bytes in a row. + */ + value[sizeof(value) - 2] = '\0'; + value[sizeof(value) - 1] = '\0'; + printf("Supported attributes:\n"); + for (p = value; *p; p += strlen(p) + 1) + { + printf("\t%s\n", p); + } + break; + + case SMB_ACL_GET: + do + { + if (the_acl == NULL) + { + if (numeric) + { + the_acl = "system.*"; + } + else + { + the_acl = "system.*+"; + } + } + ret = smbc_getxattr(path, the_acl, value, sizeof(value)); + if (ret < 0) + { + printf("Could not get attributes for [%s] %d: %s\n", + path, errno, strerror(errno)); + return 1; + } + + printf("Attributes for [%s] are:\n%s\n", path, value); + + if (stat_and_retry) + { + if (smbc_stat(path, &st) < 0) + { + perror("smbc_stat"); + return 1; + } + } + + --stat_and_retry; + } while (stat_and_retry >= 0); + break; + + case SMB_ACL_ADD: + flags = SMBC_XATTR_FLAG_CREATE; + debugstr = "add attributes"; + goto do_set; + + case SMB_ACL_MODIFY: + flags = SMBC_XATTR_FLAG_REPLACE; + debugstr = "modify attributes"; + goto do_set; + + case SMB_ACL_CHOWN: + snprintf(value, sizeof(value), + "system.nt_sec_desc.owner%s:%s", + numeric ? "" : "+", the_acl); + the_acl = value; + debugstr = "chown owner"; + goto do_set; + + case SMB_ACL_CHGRP: + snprintf(value, sizeof(value), + "system.nt_sec_desc.group%s:%s", + numeric ? "" : "+", the_acl); + the_acl = value; + debugstr = "change group"; + goto do_set; + + case SMB_ACL_SET: + flags = 0; + debugstr = "set attributes"; + + do_set: + if ((p = strchr(the_acl, ':')) == NULL) + { + printf("Missing value. ACL must be name:value pair\n"); + return 1; + } + + *p++ = '\0'; + + ret = smbc_setxattr(path, the_acl, p, strlen(p), flags); + if (ret < 0) + { + printf("Could not %s for [%s] %d: %s\n", + debugstr, path, errno, strerror(errno)); + return 1; + } + break; + + case SMB_ACL_DELETE: + ret = smbc_removexattr(path, the_acl); + if (ret < 0) + { + printf("Could not remove attribute %s for [%s] %d:%s\n", + the_acl, path, errno, strerror(errno)); + return 1; + } + break; + + default: + printf("operation not yet implemented\n"); + break; + } + + return 0; +} diff --git a/examples/libsmbclient/testacl2.c b/examples/libsmbclient/testacl2.c new file mode 100644 index 0000000..ee48b7b --- /dev/null +++ b/examples/libsmbclient/testacl2.c @@ -0,0 +1,73 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <popt.h> +#include "libsmbclient.h" +#include "get_auth_data_fn.h" + +enum acl_mode +{ + SMB_ACL_GET, + SMB_ACL_SET, + SMB_ACL_DELETE, + SMB_ACL_MODIFY, + SMB_ACL_ADD, + SMB_ACL_CHOWN, + SMB_ACL_CHGRP +}; + + +int main(int argc, const char *argv[]) +{ + int flags; + int debug = 0; + static char *the_acl = NULL; + int ret; + const char *debugstr; + char value[1024]; + SMBCCTX *context; + + if (smbc_init(get_auth_data_fn, debug) != 0) + { + printf("Could not initialize smbc_ library\n"); + return 1; + } + + context = smbc_set_context(NULL); + smbc_setOptionFullTimeNames(context, 1); + + the_acl = strdup("system.nt_sec_desc.*"); + ret = smbc_getxattr(argv[1], the_acl, value, sizeof(value)); + if (ret < 0) + { + printf("Could not get attributes for [%s] %d: %s\n", + argv[1], errno, strerror(errno)); + return 1; + } + + printf("Attributes for [%s] are:\n%s\n", argv[1], value); + + flags = 0; + debugstr = "set attributes (1st time)"; + + ret = smbc_setxattr(argv[1], the_acl, value, strlen(value), flags); + if (ret < 0) + { + printf("Could not %s for [%s] %d: %s\n", + debugstr, argv[1], errno, strerror(errno)); + return 1; + } + + flags = 0; + debugstr = "set attributes (2nd time)"; + + ret = smbc_setxattr(argv[1], the_acl, value, strlen(value), flags); + if (ret < 0) + { + printf("Could not %s for [%s] %d: %s\n", + debugstr, argv[1], errno, strerror(errno)); + return 1; + } + + return 0; +} diff --git a/examples/libsmbclient/testacl3.c b/examples/libsmbclient/testacl3.c new file mode 100644 index 0000000..e5ec2c8 --- /dev/null +++ b/examples/libsmbclient/testacl3.c @@ -0,0 +1,59 @@ +#include <sys/types.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int ret; + int debug = 0; + char value[2048]; + char path[2048]; + char * the_acl; + char * p; + SMBCCTX * context; + + smbc_init(get_auth_data_fn, debug); + + context = smbc_set_context(NULL); + smbc_setOptionFullTimeNames(context, 1); + + for (;;) + { + fprintf(stdout, "Path: "); + *path = '\0'; + p = fgets(path, sizeof(path) - 1, stdin); + if (p == NULL) { + printf("Error reading from stdin\n"); + return 1; + } + if (strlen(path) == 0) + { + return 0; + } + + p = path + strlen(path) - 1; + if (*p == '\n') + { + *p = '\0'; + } + + the_acl = strdup("system.nt_sec_desc.*+"); + ret = smbc_getxattr(path, the_acl, value, sizeof(value)); + if (ret < 0) + { + printf("Could not get attributes for [%s] %d: %s\n", + path, errno, strerror(errno)); + return 1; + } + + printf("Attributes for [%s] are:\n%s\n", path, value); + } + + return 0; +} diff --git a/examples/libsmbclient/testbrowse.c b/examples/libsmbclient/testbrowse.c new file mode 100644 index 0000000..2f2f54e --- /dev/null +++ b/examples/libsmbclient/testbrowse.c @@ -0,0 +1,281 @@ +#include <sys/types.h> +#include <unistd.h> +#include <dirent.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <popt.h> +#include <stdlib.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + +static void browse(char * path, + int scan, + int indent); + + +static void +get_auth_data_with_context_fn(SMBCCTX * context, + const char * pServer, + const char * pShare, + char * pWorkgroup, + int maxLenWorkgroup, + char * pUsername, + int maxLenUsername, + char * pPassword, + int maxLenPassword); + +int main(int argc, const char *argv[]) +{ + int debug = 0; + int debug_stderr = 0; + int no_auth = 0; + int context_auth = 0; + int scan = 0; + int iterations = -1; + int opt; + char * p; + char buf[1024]; + poptContext pc; + SMBCCTX * context; + struct poptOption long_options[] = + { + POPT_AUTOHELP + { + "debug", 'd', POPT_ARG_INT, &debug, + 0, "Set debug level", "integer" + }, + { + "stderr", 'e', POPT_ARG_NONE, &debug_stderr, + 0, "Debug log to stderr instead of stdout", "integer" + }, + { + "scan", 's', POPT_ARG_NONE, &scan, + 0, "Scan for servers and shares", "integer" + }, + { + "iterations", 'i', POPT_ARG_INT, &iterations, + 0, "Iterations", "integer" + }, + { + "noauth", 'A', POPT_ARG_NONE, &no_auth, + 0, "Do not request authentication data", "integer" + }, + { + "contextauth", 'C', POPT_ARG_NONE, &context_auth, + 0, "Use new authentication function with context", "integer" + }, + {0} + }; + + setbuf(stdout, NULL); + + pc = poptGetContext("opendir", argc, argv, long_options, 0); + + poptSetOtherOptionHelp(pc, ""); + + while ((opt = poptGetNextOpt(pc)) != -1) { + printf("Got option %d = %c\n", opt, opt); + switch (opt) { + } + } + + /* Allocate a new context */ + context = smbc_new_context(); + if (!context) { + printf("Could not allocate new smbc context\n"); + return 1; + } + + /* If we're scanning, do no requests for authentication data */ + if (scan) { + no_auth = 1; + } + + /* Set mandatory options (is that a contradiction in terms?) */ + smbc_setDebug(context, debug); + if (context_auth) { + smbc_setFunctionAuthDataWithContext(context, + get_auth_data_with_context_fn); + smbc_setOptionUserData(context, strdup("hello world")); + } else { + smbc_setFunctionAuthData(context, get_auth_data_fn); + } + + smbc_setOptionUseKerberos(context, 1); + smbc_setOptionFallbackAfterKerberos(context, 1); + + /* If we've been asked to log to stderr instead of stdout, ... */ + if (debug_stderr) { + /* ... then set the option to do so */ + smbc_setOptionDebugToStderr(context, 1); + } + + /* Initialize the context using the previously specified options */ + if (!smbc_init_context(context)) { + smbc_free_context(context, 0); + printf("Could not initialize smbc context\n"); + return 1; + } + + /* Tell the compatibility layer to use this context */ + smbc_set_context(context); + + if (scan) + { + for (; iterations != 0;) { + if (iterations > 0) { + iterations--; + } + + snprintf(buf, sizeof(buf), "smb://"); + browse(buf, scan, 0); + } + } + else + { + for (; iterations != 0;) { + if (iterations > 0) { + iterations--; + } + + fputs("url: ", stdout); + p = fgets(buf, sizeof(buf), stdin); + if (! p) + { + break; + } + + if ((p = strchr(buf, '\n')) != NULL) + { + *p = '\0'; + } + + browse(buf, scan, 0); + } + } + + exit(0); +} + +static void +get_auth_data_with_context_fn(SMBCCTX * context, + const char * pServer, + const char * pShare, + char * pWorkgroup, + int maxLenWorkgroup, + char * pUsername, + int maxLenUsername, + char * pPassword, + int maxLenPassword) +{ + printf("Authenticating with context %p", context); + if (context != NULL) { + char *user_data = smbc_getOptionUserData(context); + printf(" with user data %s", user_data); + } + printf("\n"); + + get_auth_data_fn(pServer, pShare, pWorkgroup, maxLenWorkgroup, + pUsername, maxLenUsername, pPassword, maxLenPassword); +} + +static void browse(char * path, int scan, int indent) +{ + char * p; + char buf[1024]; + int dir; + struct stat st; + struct smbc_dirent * dirent; + + if (! scan) + { + printf("Opening (%s)...\n", path); + } + + if ((dir = smbc_opendir(path)) < 0) + { + printf("Could not open directory [%s] (%d:%s)\n", + path, errno, strerror(errno)); + return; + } + + while ((dirent = smbc_readdir(dir)) != NULL) + { + printf("%*.*s%-30s", indent, indent, "", dirent->name); + + switch(dirent->smbc_type) + { + case SMBC_WORKGROUP: + printf("WORKGROUP"); + break; + + case SMBC_SERVER: + printf("SERVER"); + break; + + case SMBC_FILE_SHARE: + printf("FILE_SHARE"); + break; + + case SMBC_PRINTER_SHARE: + printf("PRINTER_SHARE"); + break; + + case SMBC_COMMS_SHARE: + printf("COMMS_SHARE"); + break; + + case SMBC_IPC_SHARE: + printf("IPC_SHARE"); + break; + + case SMBC_DIR: + printf("DIR"); + break; + + case SMBC_FILE: + printf("FILE"); + + p = path + strlen(path); + strcat(p, "/"); + strcat(p+1, dirent->name); + if (smbc_stat(path, &st) < 0) + { + printf(" unknown size (reason %d: %s)", + errno, strerror(errno)); + } + else + { + printf(" size %lu", (unsigned long) st.st_size); + } + *p = '\0'; + + break; + + case SMBC_LINK: + printf("LINK"); + break; + } + + printf("\n"); + + if (scan && + (dirent->smbc_type == SMBC_WORKGROUP || + dirent->smbc_type == SMBC_SERVER)) + { + /* + * don't append server name to workgroup; what we want is: + * + * smb://workgroup_name + * or + * smb://server_name + * + */ + snprintf(buf, sizeof(buf), "smb://%s", dirent->name); + browse(buf, scan, indent + 2); + } + } + + smbc_closedir(dir); +} diff --git a/examples/libsmbclient/testbrowse2.c b/examples/libsmbclient/testbrowse2.c new file mode 100644 index 0000000..c1d5644 --- /dev/null +++ b/examples/libsmbclient/testbrowse2.c @@ -0,0 +1,169 @@ +/* + * Alternate testbrowse utility provided by Mikhail Kshevetskiy. + * This version tests use of multiple contexts. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libsmbclient.h> + +int debuglevel = 0; +const char *workgroup = "NT"; +const char *username = "guest"; +const char *password = ""; + +typedef struct smbitem smbitem; +typedef int(*qsort_cmp)(const void *, const void *); + +struct smbitem{ + smbitem *next; + int type; + char name[1]; +}; + +static void smbc_auth_fn( + const char *server, + const char *share, + char *wrkgrp, int wrkgrplen, + char *user, int userlen, + char *passwd, int passwdlen){ + + (void) server; + (void) share; + (void) wrkgrp; + (void) wrkgrplen; + + strncpy(wrkgrp, workgroup, wrkgrplen - 1); wrkgrp[wrkgrplen - 1] = 0; + strncpy(user, username, userlen - 1); user[userlen - 1] = 0; + strncpy(passwd, password, passwdlen - 1); passwd[passwdlen - 1] = 0; +} + +static SMBCCTX* create_smbctx(void){ + SMBCCTX *ctx; + + if ((ctx = smbc_new_context()) == NULL) return NULL; + + smbc_setDebug(ctx, debuglevel); + smbc_setFunctionAuthData(ctx, smbc_auth_fn); + + if (smbc_init_context(ctx) == NULL){ + smbc_free_context(ctx, 1); + return NULL; + } + + return ctx; +} + +static void delete_smbctx(SMBCCTX* ctx){ + smbc_getFunctionPurgeCachedServers(ctx)(ctx); + smbc_free_context(ctx, 1); +} + +static smbitem* get_smbitem_list(SMBCCTX *ctx, char *smb_path){ + SMBCFILE *fd; + struct smbc_dirent *dirent; + smbitem *list = NULL, *item; + + if ((fd = smbc_getFunctionOpendir(ctx)(ctx, smb_path)) == NULL) + return NULL; + while((dirent = smbc_getFunctionReaddir(ctx)(ctx, fd)) != NULL){ + size_t slen; + if (strcmp(dirent->name, "") == 0) continue; + if (strcmp(dirent->name, ".") == 0) continue; + if (strcmp(dirent->name, "..") == 0) continue; + + slen = strlen(dirent->name)+1; + if ((item = malloc(sizeof(smbitem) + slen)) == NULL) + continue; + + item->next = list; + item->type = dirent->smbc_type; + memcpy(item->name, dirent->name, slen); + list = item; + } + smbc_getFunctionClose(ctx)(ctx, fd); + return /* smbitem_list_sort */ (list); +} + +static void print_smb_path(const char *group, const char *path){ + if ((strlen(group) == 0) && (strlen(path) == 0)) printf("/\n"); + else if (strlen(path) == 0) printf("/%s\n", group); + else{ + if (strlen(group) == 0) group = "(unknown_group)"; + printf("/%s/%s\n", group, path); + } +} + +static void recurse(SMBCCTX *ctx, const char *smb_group, char *smb_path, int maxlen){ + int len; + smbitem *list, *item; + SMBCCTX *ctx1; + + len = strlen(smb_path); + + list = get_smbitem_list(ctx, smb_path); + while(list != NULL){ + switch(list->type){ + case SMBC_WORKGROUP: + case SMBC_SERVER: + if (list->type == SMBC_WORKGROUP){ + print_smb_path(list->name, ""); + smb_group = list->name; + } + else print_smb_path(smb_group, list->name); + + if (maxlen < 7 + strlen(list->name)) break; + strncpy(smb_path + 6, list->name, maxlen - 6); + smb_path[maxlen-1] = '\0'; + if ((ctx1 = create_smbctx()) != NULL){ + recurse(ctx1, smb_group, smb_path, maxlen); + delete_smbctx(ctx1); + }else{ + recurse(ctx, smb_group, smb_path, maxlen); + smbc_getFunctionPurgeCachedServers(ctx)(ctx); + } + break; + case SMBC_FILE_SHARE: + case SMBC_DIR: + case SMBC_FILE: + if (maxlen < len + strlen(list->name) + 2) break; + + smb_path[len] = '/'; + strncpy(smb_path + len + 1, list->name, maxlen - len - 1); + smb_path[maxlen-1] = '\0'; + print_smb_path(smb_group, smb_path + 6); + if (list->type != SMBC_FILE){ + recurse(ctx, smb_group, smb_path, maxlen); + if (list->type == SMBC_FILE_SHARE) + smbc_getFunctionPurgeCachedServers(ctx)(ctx); + } + break; + } + item = list; + list = list->next; + free(item); + } + smb_path[len] = '\0'; +} + +int main(int argc, char *argv[]){ + int i; + SMBCCTX *ctx; + char smb_path[32768] = "smb://"; + + if ((ctx = create_smbctx()) == NULL){ + perror("Can't create samba context."); + return 1; + } + + if (argc == 1) recurse(ctx, "", smb_path, sizeof(smb_path)); + else for(i = 1; i < argc; i++){ + strncpy(smb_path + 6, argv[i], sizeof(smb_path) - 7); + smb_path[sizeof(smb_path) - 1] = '\0'; + recurse(ctx, "", smb_path, sizeof(smb_path)); + } + + delete_smbctx(ctx); + return 0; +} diff --git a/examples/libsmbclient/testchmod.c b/examples/libsmbclient/testchmod.c new file mode 100644 index 0000000..2341e81 --- /dev/null +++ b/examples/libsmbclient/testchmod.c @@ -0,0 +1,62 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int debug = 0; + int mode = 0666; + const char * pSmbPath = NULL; + struct stat st; + + if (argc == 1) + { + pSmbPath = "smb://RANDOM/Public/small"; + } + else if (argc == 2) + { + pSmbPath = argv[1]; + } + else if (argc == 3) + { + pSmbPath = argv[1]; + mode = (int) strtol(argv[2], NULL, 8); + } + else + { + printf("usage: " + "%s [ smb://path/to/file [ octal_mode ] ]\n", + argv[0]); + return 1; + } + + smbc_init(get_auth_data_fn, debug); + + if (smbc_stat(pSmbPath, &st) < 0) + { + perror("smbc_stat"); + return 1; + } + + printf("\nBefore chmod: mode = %04o\n", (unsigned int)st.st_mode); + + if (smbc_chmod(pSmbPath, mode) < 0) + { + perror("smbc_chmod"); + return 1; + } + + if (smbc_stat(pSmbPath, &st) < 0) + { + perror("smbc_stat"); + return 1; + } + + printf("After chmod: mode = %04o\n", (unsigned int)st.st_mode); + + return 0; +} diff --git a/examples/libsmbclient/testctx.c b/examples/libsmbclient/testctx.c new file mode 100644 index 0000000..e410731 --- /dev/null +++ b/examples/libsmbclient/testctx.c @@ -0,0 +1,33 @@ +#include <libsmbclient.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +static void create_and_destroy_context (void) +{ + int i; + SMBCCTX *ctx; + ctx = smbc_new_context (); + /* Both should do the same thing */ + smbc_setOptionDebugToStderr(ctx, 1); + smbc_option_set(ctx, strdup("debug_to_stderr"), 1); + smbc_setDebug(ctx, 1); + i = smbc_getDebug(ctx); + if (i != 1) { + printf("smbc_getDebug() did not return debug level set\n"); + exit(1); + } + if (!smbc_getOptionDebugToStderr(ctx)) { + printf("smbc_setOptionDebugToStderr() did not stick\n"); + exit(1); + } + smbc_init_context (ctx); + smbc_free_context (ctx, 1); +} + +int main (int argc, char **argv) +{ + create_and_destroy_context (); + create_and_destroy_context (); + return 0; +} diff --git a/examples/libsmbclient/testfstatvfs.c b/examples/libsmbclient/testfstatvfs.c new file mode 100644 index 0000000..9a4063e --- /dev/null +++ b/examples/libsmbclient/testfstatvfs.c @@ -0,0 +1,134 @@ +#include <sys/types.h> +#include <sys/statvfs.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int fd; + int ret; + int debug = 0; + char * p; + char path[2048]; + struct stat statbuf; + struct statvfs statvfsbuf; + + smbc_init(get_auth_data_fn, debug); + + for (;;) + { + fprintf(stdout, "Path: "); + *path = '\0'; + p = fgets(path, sizeof(path) - 1, stdin); + if (p == NULL) { + fprintf(stderr, "failed to read from stdin\n"); + return 1; + } + if (strlen(path) == 0) + { + return 0; + } + + p = path + strlen(path) - 1; + if (*p == '\n') + { + *p = '\0'; + } + + /* Determine if it's a file or a folder */ + if (smbc_stat(path, &statbuf) < 0) + { + perror("smbc_stat"); + continue; + } + + if (S_ISREG(statbuf.st_mode)) + { + if ((fd = smbc_open(path, O_RDONLY, 0)) < 0) + { + perror("smbc_open"); + continue; + } + } + else + { + if ((fd = smbc_opendir(path)) < 0) + { + perror("smbc_opendir"); + continue; + } + } + + ret = smbc_fstatvfs(fd, &statvfsbuf); + + smbc_close(fd); + + if (ret < 0) + { + perror("fstatvfs"); + } + else + { + printf("\n"); + printf("Block Size: %lu\n", statvfsbuf.f_bsize); + printf("Fragment Size: %lu\n", statvfsbuf.f_frsize); + printf("Blocks: %llu\n", + (unsigned long long) statvfsbuf.f_blocks); + printf("Free Blocks: %llu\n", + (unsigned long long) statvfsbuf.f_bfree); + printf("Available Blocks: %llu\n", + (unsigned long long) statvfsbuf.f_bavail); + printf("Files : %llu\n", + (unsigned long long) statvfsbuf.f_files); + printf("Free Files: %llu\n", + (unsigned long long) statvfsbuf.f_ffree); + printf("Available Files: %llu\n", + (unsigned long long) statvfsbuf.f_favail); +#ifdef HAVE_FSID_INT + printf("File System ID: %lu\n", + (unsigned long) statvfsbuf.f_fsid); +#endif + printf("\n"); + + printf("Flags: 0x%lx\n", statvfsbuf.f_flag); + printf("Extended Features: "); + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_NO_UNIXCIFS) + { + printf("NO_UNIXCIFS "); + } + else + { + printf("unixcifs "); + } + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_CASE_INSENSITIVE) + { + printf("CASE_INSENSITIVE "); + } + else + { + printf("case_sensitive "); + } + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_DFS) + { + printf("DFS "); + } + else + { + printf("no_dfs "); + } + + printf("\n"); + } + } + + return 0; +} diff --git a/examples/libsmbclient/testnotify.c b/examples/libsmbclient/testnotify.c new file mode 100644 index 0000000..8760cf0 --- /dev/null +++ b/examples/libsmbclient/testnotify.c @@ -0,0 +1,82 @@ +#include <sys/types.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <libsmbclient.h> +#include <inttypes.h> +#include "get_auth_data_fn.h" + +static int notify_cb(const struct smbc_notify_callback_action *actions, + size_t num_actions, void *private_data) +{ + int *count = private_data; + size_t i; + + printf("%zu\n", num_actions); + + for (i=0; i<num_actions; i++) { + const struct smbc_notify_callback_action *a = &actions[i]; + printf("%s: %"PRIu32"\n", a->filename, a->action); + } + + *count -= 1; + if (*count < 0) { + return 1; + } + + return 0; +} + +int main(int argc, char * argv[]) +{ + int fd; + int ret; + int debug = 0; + int saved_errno; + char path[2048]; + char * p; + int count = 1000; + + smbc_init(get_auth_data_fn, debug); + + fprintf(stdout, "Path: "); + *path = '\0'; + p = fgets(path, sizeof(path) - 1, stdin); + if (p == NULL) { + fprintf(stderr, "error reading from stdin\n"); + return 1; + } + if (strlen(path) == 0) { + return 0; + } + + p = path + strlen(path) - 1; + if (*p == '\n') { + *p = '\0'; + } + + fd = smbc_opendir(path); + if (fd < 0) { + perror("smbc_open"); + return 1; + } + + ret = smbc_notify(fd, 1, + SMBC_NOTIFY_CHANGE_SECURITY| + SMBC_NOTIFY_CHANGE_FILE_NAME, + 1000, notify_cb, &count); + if (ret < 0) { + saved_errno = errno; + } + + smbc_close(fd); + + if (ret < 0) { + errno = saved_errno; + perror("notify"); + } + + return 0; +} diff --git a/examples/libsmbclient/testread.c b/examples/libsmbclient/testread.c new file mode 100644 index 0000000..d9722ad --- /dev/null +++ b/examples/libsmbclient/testread.c @@ -0,0 +1,66 @@ +#include <sys/types.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int fd; + int ret; + int debug = 0; + int savedErrno; + char buffer[2048]; + char path[2048]; + char * p; + + smbc_init(get_auth_data_fn, debug); + + for (;;) + { + fprintf(stdout, "Path: "); + *path = '\0'; + p = fgets(path, sizeof(path) - 1, stdin); + if (p == NULL) { + fprintf(stderr, "failed to read from stdin\n"); + return 1; + } + if (strlen(path) == 0) + { + return 0; + } + + p = path + strlen(path) - 1; + if (*p == '\n') + { + *p = '\0'; + } + + if ((fd = smbc_open(path, O_RDONLY, 0)) < 0) + { + perror("smbc_open"); + continue; + } + + do + { + ret = smbc_read(fd, buffer, sizeof(buffer)); + savedErrno = errno; + if (ret > 0) fwrite(buffer, 1, ret, stdout); + } while (ret > 0); + + smbc_close(fd); + + if (ret < 0) + { + errno = savedErrno; + perror("read"); + } + } + + return 0; +} diff --git a/examples/libsmbclient/testsmbc.c b/examples/libsmbclient/testsmbc.c new file mode 100644 index 0000000..a61d38e --- /dev/null +++ b/examples/libsmbclient/testsmbc.c @@ -0,0 +1,291 @@ +/* + Unix SMB/CIFS implementation. + SMB client library test program + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000 + Copyright (C) John Terpsra 2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <errno.h> +#include <time.h> +#include <sys/time.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include "libsmbclient.h" +#include "get_auth_data_fn.h" + +int main(int argc, char *argv[]) +{ + int err, fd, dh1, dsize, dirc; + const char *file = "smb://samba/public/testfile.txt"; + const char *file2 = "smb://samba/public/testfile2.txt"; + char buff[256]; + char dirbuf[512]; + char *dirp; + struct stat st1, st2; + + err = smbc_init(get_auth_data_fn, 10); /* Initialize things */ + + if (err < 0) { + + fprintf(stderr, "Initializing the smbclient library ...: %s\n", strerror(errno)); + + } + + if (argc > 1) { + + if ((dh1 = smbc_opendir(argv[1]))<1) { + + fprintf(stderr, "Could not open directory: %s: %s\n", + argv[1], strerror(errno)); + + exit(1); + + } + + fprintf(stdout, "Directory handle: %u\n", dh1); + + /* Now, list those directories, but in funny ways ... */ + + dirp = (char *)dirbuf; + + if ((dirc = smbc_getdents(dh1, (struct smbc_dirent *)dirp, + sizeof(dirbuf))) < 0) { + + fprintf(stderr, "Problems getting directory entries: %s\n", + strerror(errno)); + + exit(1); + + } + + /* Now, process the list of names ... */ + + fprintf(stdout, "Directory listing, size = %u\n", dirc); + + while (dirc > 0) { + + dsize = ((struct smbc_dirent *)dirp)->dirlen; + fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n", + ((struct smbc_dirent *)dirp)->smbc_type, + ((struct smbc_dirent *)dirp)->name, + ((struct smbc_dirent *)dirp)->comment); + + dirp += dsize; + dirc -= dsize; + + } + + dirp = (char *)dirbuf; + + exit(1); + + } + + /* For now, open a file on a server that is hard coded ... later will + * read from the command line ... + */ + + fd = smbc_open(file, O_RDWR | O_CREAT | O_TRUNC, 0666); + + if (fd < 0) { + + fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + fprintf(stdout, "Opened or created file: %s\n", file); + + /* Now, write some date to the file ... */ + + memset(buff, '\0', sizeof(buff)); + snprintf(buff, sizeof(buff), "%s", "Some test data for the moment ..."); + + err = smbc_write(fd, buff, sizeof(buff)); + + if (err < 0) { + + fprintf(stderr, "writing file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + fprintf(stdout, "Wrote %lu bytes to file: %s\n", + (unsigned long) sizeof(buff), buff); + + /* Now, seek the file back to offset 0 */ + + err = smbc_lseek(fd, SEEK_SET, 0); + + if (err < 0) { + + fprintf(stderr, "Seeking file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + fprintf(stdout, "Completed lseek on file: %s\n", file); + + /* Now, read the file contents back ... */ + + err = smbc_read(fd, buff, sizeof(buff)); + + if (err < 0) { + + fprintf(stderr, "Reading file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + fprintf(stdout, "Read file: %s\n", buff); /* Should check the contents */ + + fprintf(stdout, "Now fstat'ing file: %s\n", file); + + err = smbc_fstat(fd, &st1); + + if (err < 0) { + + fprintf(stderr, "Fstat'ing file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + + /* Now, close the file ... */ + + err = smbc_close(fd); + + if (err < 0) { + + fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno)); + + } + + /* Now, rename the file ... */ + + err = smbc_rename(file, file2); + + if (err < 0) { + + fprintf(stderr, "Renaming file: %s to %s: %s\n", file, file2, strerror(errno)); + + } + + fprintf(stdout, "Renamed file %s to %s\n", file, file2); + + /* Now, create a file and delete it ... */ + + fprintf(stdout, "Now, creating file: %s so we can delete it.\n", file); + + fd = smbc_open(file, O_RDWR | O_CREAT, 0666); + + if (fd < 0) { + + fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + fprintf(stdout, "Opened or created file: %s\n", file); + + err = smbc_close(fd); + + if (err < 0) { + + fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + /* Now, delete the file ... */ + + fprintf(stdout, "File %s created, now deleting ...\n", file); + + err = smbc_unlink(file); + + if (err < 0) { + + fprintf(stderr, "Deleting file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + /* Now, stat the file, file 2 ... */ + + fprintf(stdout, "Now stat'ing file: %s\n", file); + + err = smbc_stat(file2, &st2); + + if (err < 0) { + + fprintf(stderr, "Stat'ing file: %s: %s\n", file, strerror(errno)); + exit(0); + + } + + fprintf(stdout, "Stat'ed file: %s. Size = %d, mode = %04X\n", file2, + (int)st2.st_size, (unsigned int)st2.st_mode); + fprintf(stdout, " time: %s\n", ctime(&st2.st_atime)); + fprintf(stdout, "Earlier stat: %s, Size = %d, mode = %04X\n", file, + (int)st1.st_size, (unsigned int)st1.st_mode); + fprintf(stdout, " time: %s\n", ctime(&st1.st_atime)); + + /* Now, make a directory ... */ + + fprintf(stdout, "Making directory smb://samba/public/make-dir\n"); + + if (smbc_mkdir("smb://samba/public/make-dir", 0666) < 0) { + + fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n", + strerror(errno)); + + if (errno == EEXIST) { /* Try to delete the directory */ + + fprintf(stdout, "Trying to delete directory: smb://samba/public/make-dir\n"); + + if (smbc_rmdir("smb://samba/public/make-dir") < 0) { /* Error */ + + fprintf(stderr, "Error removing directory: smb://samba/public/make-dir: %s\n", strerror(errno)); + + exit(0); + + } + + fprintf(stdout, "Making directory: smb://samba/public/make-dir\n"); + + if (smbc_mkdir("smb://samba/public/make-dir", 666) < 0) { + + fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n", + strerror(errno)); + + fprintf(stderr, "I give up!\n"); + + exit(1); + + } + + } + + exit(0); + + } + + fprintf(stdout, "Made dir: make-dir\n"); + return 0; +} diff --git a/examples/libsmbclient/teststat.c b/examples/libsmbclient/teststat.c new file mode 100644 index 0000000..079ac89 --- /dev/null +++ b/examples/libsmbclient/teststat.c @@ -0,0 +1,110 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <libsmbclient.h> +#include <stdbool.h> +#include "get_auth_data_fn.h" + +static const char *filetypestr(mode_t mode) +{ + if (S_ISREG(mode)) { + return "regular file"; + } + if (S_ISDIR(mode)) { + return "directory"; + } + if (S_ISFIFO(mode)) { + return "fifo"; + } + if (S_ISLNK(mode)) { + return "symbolic link"; + } + if (S_ISSOCK(mode)) { + return "socket"; + } + if (S_ISCHR(mode)) { + return "character special file"; + } + if (S_ISBLK(mode)) { + return "block special file"; + } + return "unknown file type"; +} + +int main(int argc, char * argv[]) +{ + SMBCCTX *ctx = NULL; + int debug = 0; + char m_time[32]; + char c_time[32]; + char a_time[32]; + const char * pSmbPath = NULL; + const char * pLocalPath = NULL; + struct stat st; + int ret; + + if (argc == 1) { + pSmbPath = "smb://RANDOM/Public/small"; + pLocalPath = "/random/home/samba/small"; + } + else if (argc == 2) { + pSmbPath = argv[1]; + pLocalPath = NULL; + } + else if (argc == 3) { + pSmbPath = argv[1]; + pLocalPath = argv[2]; + } else { + printf("usage: %s [ smb://path/to/file " + "[ /nfs/or/local/path/to/file ] ]\n", + argv[0]); + return 1; + } + + ctx = smbc_new_context(); + if (ctx == NULL) { + perror("smbc_new_context failed"); + return 1; + } + + smbc_setOptionDebugToStderr(ctx, 1); + smbc_setDebug(ctx, debug); + smbc_init_context(ctx); + smbc_setFunctionAuthData(ctx, get_auth_data_fn); + smbc_setOptionPosixExtensions(ctx, true); + + ret = smbc_getFunctionStat(ctx)(ctx, pSmbPath, &st); + if (ret < 0) { + perror("smbc_stat"); + return 1; + } + + printf("\nSAMBA\n mtime:%jd/%s ctime:%jd/%s atime:%jd/%s %s\n", + (intmax_t)st.st_mtime, + ctime_r(&st.st_mtime, m_time), + (intmax_t)st.st_ctime, + ctime_r(&st.st_ctime, c_time), + (intmax_t)st.st_atime, + ctime_r(&st.st_atime, a_time), + filetypestr(st.st_mode)); + + if (pLocalPath != NULL) { + ret = stat(pLocalPath, &st); + if (ret < 0) { + perror("stat"); + return 1; + } + + printf("LOCAL\n mtime:%jd/%s ctime:%jd/%s atime:%jd/%s %s\n", + (intmax_t)st.st_mtime, + ctime_r(&st.st_mtime, m_time), + (intmax_t)st.st_ctime, + ctime_r(&st.st_ctime, c_time), + (intmax_t)st.st_atime, + ctime_r(&st.st_atime, a_time), + filetypestr(st.st_mode)); + } + + return 0; +} diff --git a/examples/libsmbclient/teststat2.c b/examples/libsmbclient/teststat2.c new file mode 100644 index 0000000..04994b7 --- /dev/null +++ b/examples/libsmbclient/teststat2.c @@ -0,0 +1,70 @@ +#include <libsmbclient.h> +#include <sys/stat.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include "get_auth_data_fn.h" + +/* + * This test is intended to ensure that the timestamps returned by + * libsmbclient are the same as timestamps returned by the local system. To + * test this, we assume a working Samba environment, and access the same + * file via SMB and locally (or NFS). + * + */ + + +static int gettime(const char * pUrl, + const char * pLocalPath); + + +int main(int argc, char* argv[]) +{ + if(argc != 3) + { + printf("usage: %s <file_url> <file_localpath>\n", argv[0]); + return 1; + } + + gettime(argv[1], argv[2]); + return 0; +} + + +static int gettime(const char * pUrl, + const char * pLocalPath) +{ + struct stat st; + char m_time[32]; + char c_time[32]; + char a_time[32]; + + smbc_init(get_auth_data_fn, 0); + + if (smbc_stat(pUrl, &st) < 0) + { + perror("smbc_stat"); + return 1; + } + + printf("SAMBA\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n", + (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time), + (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time), + (long long)st.st_atime, ctime_r(&st.st_atime, a_time)); + + + /* check the stat on this file */ + if (stat(pLocalPath, &st) < 0) + { + perror("stat"); + return 1; + } + + printf("LOCAL\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n", + (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time), + (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time), + (long long)st.st_atime, ctime_r(&st.st_atime, a_time)); + + + return 0; +} diff --git a/examples/libsmbclient/teststat3.c b/examples/libsmbclient/teststat3.c new file mode 100644 index 0000000..3669d70 --- /dev/null +++ b/examples/libsmbclient/teststat3.c @@ -0,0 +1,74 @@ +#include <libsmbclient.h> +#include <sys/stat.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include "get_auth_data_fn.h" + +/* + * This test is intended to ensure that the timestamps returned by + * libsmbclient using smbc_stat() are the same as those returned by + * smbc_fstat(). + */ + + +int main(int argc, char* argv[]) +{ + int fd; + struct stat st1; + struct stat st2; + char * pUrl = argv[1]; + + if(argc != 2) + { + printf("usage: %s <file_url>\n", argv[0]); + return 1; + } + + + smbc_init(get_auth_data_fn, 0); + + if (smbc_stat(pUrl, &st1) < 0) + { + perror("smbc_stat"); + return 1; + } + + if ((fd = smbc_open(pUrl, O_RDONLY, 0)) < 0) + { + perror("smbc_open"); + return 1; + } + + if (smbc_fstat(fd, &st2) < 0) + { + perror("smbc_fstat"); + return 1; + } + + smbc_close(fd); + +#define COMPARE(name, field) \ + if (st1.field != st2.field) \ + { \ + printf("Field " name " MISMATCH: st1=%lu, st2=%lu\n", \ + (unsigned long) st1.field, \ + (unsigned long) st2.field); \ + } + + COMPARE("st_dev", st_dev); + COMPARE("st_ino", st_ino); + COMPARE("st_mode", st_mode); + COMPARE("st_nlink", st_nlink); + COMPARE("st_uid", st_uid); + COMPARE("st_gid", st_gid); + COMPARE("st_rdev", st_rdev); + COMPARE("st_size", st_size); + COMPARE("st_blksize", st_blksize); + COMPARE("st_blocks", st_blocks); + COMPARE("st_atime", st_atime); + COMPARE("st_mtime", st_mtime); + COMPARE("st_ctime", st_ctime); + + return 0; +} diff --git a/examples/libsmbclient/teststatvfs.c b/examples/libsmbclient/teststatvfs.c new file mode 100644 index 0000000..44d4ed2 --- /dev/null +++ b/examples/libsmbclient/teststatvfs.c @@ -0,0 +1,106 @@ +#include <sys/types.h> +#include <sys/statvfs.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int ret; + int debug = 0; + char * p; + char path[2048]; + struct statvfs statvfsbuf; + + smbc_init(get_auth_data_fn, debug); + + for (;;) + { + fprintf(stdout, "Path: "); + *path = '\0'; + p = fgets(path, sizeof(path) - 1, stdin); + if (p == NULL) { + fprintf(stderr, "failed to read from stdin\n"); + return 1; + } + if (strlen(path) == 0) + { + return 0; + } + + p = path + strlen(path) - 1; + if (*p == '\n') + { + *p = '\0'; + } + + ret = smbc_statvfs(path, &statvfsbuf); + + if (ret < 0) + { + perror("fstatvfs"); + } + else + { + printf("\n"); + printf("Block Size: %lu\n", statvfsbuf.f_bsize); + printf("Fragment Size: %lu\n", statvfsbuf.f_frsize); + printf("Blocks: %llu\n", + (unsigned long long) statvfsbuf.f_blocks); + printf("Free Blocks: %llu\n", + (unsigned long long) statvfsbuf.f_bfree); + printf("Available Blocks: %llu\n", + (unsigned long long) statvfsbuf.f_bavail); + printf("Files : %llu\n", + (unsigned long long) statvfsbuf.f_files); + printf("Free Files: %llu\n", + (unsigned long long) statvfsbuf.f_ffree); + printf("Available Files: %llu\n", + (unsigned long long) statvfsbuf.f_favail); +#ifdef HAVE_FSID_INT + printf("File System ID: %lu\n", + (unsigned long) statvfsbuf.f_fsid); +#endif + printf("\n"); + + printf("Flags: 0x%lx\n", statvfsbuf.f_flag); + printf("Extended Features: "); + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_NO_UNIXCIFS) + { + printf("NO_UNIXCIFS "); + } + else + { + printf("unixcifs "); + } + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_CASE_INSENSITIVE) + { + printf("CASE_INSENSITIVE "); + } + else + { + printf("case_sensitive "); + } + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_DFS) + { + printf("DFS "); + } + else + { + printf("no_dfs "); + } + + printf("\n"); + } + } + + return 0; +} diff --git a/examples/libsmbclient/testtruncate.c b/examples/libsmbclient/testtruncate.c new file mode 100644 index 0000000..bbc70e9 --- /dev/null +++ b/examples/libsmbclient/testtruncate.c @@ -0,0 +1,80 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int fd; + int ret; + int debug = 0; + int savedErrno; + char buffer[128]; + struct stat st; + + if (argc != 2) + { + printf("usage: " + "%s smb://path/to/file\n", + argv[0]); + return 1; + } + + smbc_init(get_auth_data_fn, debug); + + if ((fd = smbc_open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0) + { + perror("smbc_open"); + return 1; + } + + snprintf(buffer, sizeof(buffer), "%s", "Hello world.\nThis is a test.\n"); + + ret = smbc_write(fd, buffer, strlen(buffer)); + savedErrno = errno; + smbc_close(fd); + + if (ret < 0) + { + errno = savedErrno; + perror("write"); + } + + if (smbc_stat(argv[1], &st) < 0) + { + perror("smbc_stat"); + return 1; + } + + printf("Original size: %lu\n", (unsigned long) st.st_size); + + if ((fd = smbc_open(argv[1], O_WRONLY, 0)) < 0) + { + perror("smbc_open"); + return 1; + } + + ret = smbc_ftruncate(fd, 13); + savedErrno = errno; + smbc_close(fd); + if (ret < 0) + { + errno = savedErrno; + perror("smbc_ftruncate"); + return 1; + } + + if (smbc_stat(argv[1], &st) < 0) + { + perror("smbc_stat"); + return 1; + } + + printf("New size: %lu\n", (unsigned long) st.st_size); + + return 0; +} diff --git a/examples/libsmbclient/testutime.c b/examples/libsmbclient/testutime.c new file mode 100644 index 0000000..378b0e9 --- /dev/null +++ b/examples/libsmbclient/testutime.c @@ -0,0 +1,75 @@ +#include "config.h" +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int debug = 0; + char m_time[32]; + char c_time[32]; + char a_time[32]; + const char * pSmbPath = NULL; + time_t t = time(NULL); + struct stat st; + struct utimbuf utimbuf; + + if (argc == 1) + { + pSmbPath = "smb://RANDOM/Public/small"; + } + else if (argc == 2) + { + pSmbPath = argv[1]; + } + else if (argc == 3) + { + pSmbPath = argv[1]; + t = (time_t) strtol(argv[2], NULL, 10); + } + else + { + printf("usage: " + "%s [ smb://path/to/file [ mtime ] ]\n", + argv[0]); + return 1; + } + + smbc_init(get_auth_data_fn, debug); + + if (smbc_stat(pSmbPath, &st) < 0) + { + perror("smbc_stat"); + return 1; + } + + printf("Before\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n", + (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time), + (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time), + (long long)st.st_atime, ctime_r(&st.st_atime, a_time)); + + utimbuf.actime = t; /* unchangeable (won't change) */ + utimbuf.modtime = t; /* this one should succeed */ + if (smbc_utime(pSmbPath, &utimbuf) < 0) + { + perror("smbc_utime"); + return 1; + } + + if (smbc_stat(pSmbPath, &st) < 0) + { + perror("smbc_stat"); + return 1; + } + + printf("After\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n", + (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time), + (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time), + (long long)st.st_atime, ctime_r(&st.st_atime, a_time)); + + return 0; +} diff --git a/examples/libsmbclient/testwrite.c b/examples/libsmbclient/testwrite.c new file mode 100644 index 0000000..0e728e0 --- /dev/null +++ b/examples/libsmbclient/testwrite.c @@ -0,0 +1,72 @@ +#include <sys/types.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <libsmbclient.h> +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int fd; + int ret; + int debug = 0; + int savedErrno; + char buffer[2048]; + char path[2048]; + char * p; + + smbc_init(get_auth_data_fn, debug); + + printf("CAUTION: This program will overwrite a file. " + "Press ENTER to continue."); + p = fgets(buffer, sizeof(buffer), stdin); + if (p == NULL) { + fprintf(stderr, "failed to read from stdin\n"); + return 1; + } + + + for (;;) + { + fprintf(stdout, "\nPath: "); + *path = '\0'; + p = fgets(path, sizeof(path) - 1, stdin); + if (p == NULL) { + fprintf(stderr, "failed to read from stdin\n"); + return 1; + } + if (strlen(path) == 0) + { + return 0; + } + + p = path + strlen(path) - 1; + if (*p == '\n') + { + *p = '\0'; + } + + if ((fd = smbc_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0) + { + perror("smbc_open"); + continue; + } + + snprintf(buffer, sizeof(buffer), "%s", "Hello world\n"); + + ret = smbc_write(fd, buffer, strlen(buffer)); + savedErrno = errno; + smbc_close(fd); + + if (ret < 0) + { + errno = savedErrno; + perror("write"); + } + } + + return 0; +} diff --git a/examples/libsmbclient/tree.c b/examples/libsmbclient/tree.c new file mode 100644 index 0000000..07847c8 --- /dev/null +++ b/examples/libsmbclient/tree.c @@ -0,0 +1,812 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB client GTK+ tree-based application + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2001 + Copyright (C) John Terpstra 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* example-gtk+ application, ripped off from the gtk+ tree.c sample */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <gtk/gtk.h> +#include "libsmbclient.h" + +static GtkWidget *clist; + +struct tree_data { + + guint32 type; /* Type of tree item, an SMBC_TYPE */ + char name[256]; /* May need to change this later */ + +}; + +void error_message(gchar *message) { + + GtkWidget *dialog, *label, *okay_button; + + /* Create the widgets */ + + dialog = gtk_dialog_new(); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + label = gtk_label_new (message); + okay_button = gtk_button_new_with_label("Okay"); + + /* Ensure that the dialog box is destroyed when the user clicks ok. */ + + gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), + okay_button); + + /* Add the label, and show everything we've added to the dialog. */ + + gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), + label); + gtk_widget_show_all (dialog); +} + +/* + * We are given a widget, and we want to retrieve its URL so we + * can do a directory listing. + * + * We walk back up the tree, picking up pieces until we hit a server or + * workgroup type and return a path from there + */ + +static char path_string[1024]; + +char *get_path(GtkWidget *item) +{ + GtkWidget *p = item; + struct tree_data *pd; + char *comps[1024]; /* We keep pointers to the components here */ + int i = 0, j, level,type; + + /* Walk back up the tree, getting the private data */ + + level = GTK_TREE(item->parent)->level; + + /* Pick up this item's component info */ + + pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(item)); + + comps[i++] = pd->name; + type = pd->type; + + while (level > 0 && type != SMBC_SERVER && type != SMBC_WORKGROUP) { + + /* Find the parent and extract the data etc ... */ + + p = GTK_WIDGET(p->parent); + p = GTK_WIDGET(GTK_TREE(p)->tree_owner); + + pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(p)); + + level = GTK_TREE(item->parent)->level; + + comps[i++] = pd->name; + type = pd->type; + + } + + /* + * Got a list of comps now, should check that we did not hit a workgroup + * when we got other things as well ... Later + * + * Now, build the path + */ + + snprintf(path_string, sizeof(path_string), "smb:/"); + + for (j = i - 1; j >= 0; j--) { + + strncat(path_string, "/", sizeof(path_string) - strlen(path_string)); + strncat(path_string, comps[j], sizeof(path_string) - strlen(path_string)); + + } + + fprintf(stdout, "Path string = %s\n", path_string); + + return path_string; + +} + +struct tree_data *make_tree_data(guint32 type, const char *name) +{ + struct tree_data *p = (struct tree_data *)malloc(sizeof(struct tree_data)); + + if (p) { + + p->type = type; + strncpy(p->name, name, sizeof(p->name)); + + } + + return p; + +} + +/* Note that this is called every time the user clicks on an item, + whether it is already selected or not. */ +static void cb_select_child (GtkWidget *root_tree, GtkWidget *child, + GtkWidget *subtree) +{ + gint dh, err, dirlen; + char dirbuf[512]; + struct smbc_dirent *dirp; + struct stat st1; + char path[1024], path1[1024]; + + g_print ("select_child called for root tree %p, subtree %p, child %p\n", + root_tree, subtree, child); + + /* Now, figure out what it is, and display it in the clist ... */ + + gtk_clist_clear(GTK_CLIST(clist)); /* Clear the CLIST */ + + /* Now, get the private data for the subtree */ + + strncpy(path, get_path(child), 1024); + + if ((dh = smbc_opendir(path)) < 0) { /* Handle error */ + + g_print("cb_select_child: Could not open dir %s, %s\n", path, + strerror(errno)); + + gtk_main_quit(); + + return; + + } + + while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, + sizeof(dirbuf))) != 0) { + + if (err < 0) { + + g_print("cb_select_child: Could not read dir %s, %s\n", path, + strerror(errno)); + + gtk_main_quit(); + + return; + + } + + dirp = (struct smbc_dirent *)dirbuf; + + while (err > 0) { + gchar col1[128], col2[128], col3[128], col4[128]; + gchar *rowdata[4] = {col1, col2, col3, col4}; + + dirlen = dirp->dirlen; + + /* Format each of the items ... */ + + strncpy(col1, dirp->name, 128); + + col2[0] = col3[0] = col4[0] = (char)0; + + switch (dirp->smbc_type) { + + case SMBC_WORKGROUP: + + break; + + case SMBC_SERVER: + + strncpy(col2, (dirp->comment?dirp->comment:""), 128); + + break; + + case SMBC_FILE_SHARE: + + strncpy(col2, (dirp->comment?dirp->comment:""), 128); + + break; + + case SMBC_PRINTER_SHARE: + + strncpy(col2, (dirp->comment?dirp->comment:""), 128); + break; + + case SMBC_COMMS_SHARE: + + break; + + case SMBC_IPC_SHARE: + + break; + + case SMBC_DIR: + case SMBC_FILE: + + /* Get stats on the file/dir and see what we have */ + + if ((strcmp(dirp->name, ".") != 0) && + (strcmp(dirp->name, "..") != 0)) { + + strncpy(path1, path, sizeof(path1)); + strncat(path1, "/", sizeof(path) - strlen(path)); + strncat(path1, dirp->name, sizeof(path) - strlen(path)); + + if (smbc_stat(path1, &st1) < 0) { + + if (errno != EBUSY) { + + g_print("cb_select_child: Could not stat file %s, %s\n", path1, + strerror(errno)); + + gtk_main_quit(); + + return; + + } + else { + + strncpy(col2, "Device or resource busy", sizeof(col2)); + + } + } + else { + /* Now format each of the relevant things ... */ + + snprintf(col2, sizeof(col2), "%c%c%c%c%c%c%c%c%c(%0X)", + (st1.st_mode&S_IRUSR?'r':'-'), + (st1.st_mode&S_IWUSR?'w':'-'), + (st1.st_mode&S_IXUSR?'x':'-'), + (st1.st_mode&S_IRGRP?'r':'-'), + (st1.st_mode&S_IWGRP?'w':'-'), + (st1.st_mode&S_IXGRP?'x':'-'), + (st1.st_mode&S_IROTH?'r':'-'), + (st1.st_mode&S_IWOTH?'w':'-'), + (st1.st_mode&S_IXOTH?'x':'-'), + st1.st_mode); + snprintf(col3, sizeof(col3), "%u", st1.st_size); + snprintf(col4, sizeof(col4), "%s", ctime(&st1.st_mtime)); + } + } + + break; + + default: + + break; + } + + gtk_clist_append(GTK_CLIST(clist), rowdata); + + dirp = (struct smbc_dirent *) ((char *) dirp + dirlen); + err -= dirlen; + + } + + } + +} + +/* Note that this is never called */ +static void cb_unselect_child( GtkWidget *root_tree, + GtkWidget *child, + GtkWidget *subtree ) +{ + g_print ("unselect_child called for root tree %p, subtree %p, child %p\n", + root_tree, subtree, child); +} + +/* for all the GtkItem:: and GtkTreeItem:: signals */ +static void cb_itemsignal( GtkWidget *item, + gchar *signame ) +{ + GtkWidget *real_tree, *aitem, *subtree; + gchar *name; + GtkLabel *label; + gint dh, err, dirlen, level; + char dirbuf[512]; + struct smbc_dirent *dirp; + + label = GTK_LABEL (GTK_BIN (item)->child); + /* Get the text of the label */ + gtk_label_get (label, &name); + + level = GTK_TREE(item->parent)->level; + + /* Get the level of the tree which the item is in */ + g_print ("%s called for item %s->%p, level %d\n", signame, name, + item, GTK_TREE (item->parent)->level); + + real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */ + + if (strncmp(signame, "expand", 6) == 0) { /* Expand called */ + char server[128]; + + if ((dh = smbc_opendir(get_path(item))) < 0) { /* Handle error */ + gchar errmsg[256]; + + g_print("cb_itemsignal: Could not open dir %s, %s\n", get_path(item), + strerror(errno)); + + snprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not open dir %s, %s\n", get_path(item), strerror(errno)); + + error_message(errmsg); + + /* gtk_main_quit();*/ + + return; + + } + + while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, + sizeof(dirbuf))) != 0) { + + if (err < 0) { /* An error, report it */ + gchar errmsg[256]; + + g_print("cb_itemsignal: Could not read dir smbc://, %s\n", + strerror(errno)); + + snprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not read dir smbc://, %s\n", strerror(errno)); + + error_message(errmsg); + + /* gtk_main_quit();*/ + + return; + + } + + dirp = (struct smbc_dirent *)dirbuf; + + while (err > 0) { + struct tree_data *my_data; + + dirlen = dirp->dirlen; + + my_data = make_tree_data(dirp->smbc_type, dirp->name); + + if (!my_data) { + + g_print("Could not allocate space for tree_data: %s\n", + dirp->name); + + gtk_main_quit(); + return; + + } + + aitem = gtk_tree_item_new_with_label(dirp->name); + + /* Connect all GtkItem:: and GtkTreeItem:: signals */ + gtk_signal_connect (GTK_OBJECT(aitem), "select", + GTK_SIGNAL_FUNC(cb_itemsignal), "select"); + gtk_signal_connect (GTK_OBJECT(aitem), "deselect", + GTK_SIGNAL_FUNC(cb_itemsignal), "deselect"); + gtk_signal_connect (GTK_OBJECT(aitem), "toggle", + GTK_SIGNAL_FUNC(cb_itemsignal), "toggle"); + gtk_signal_connect (GTK_OBJECT(aitem), "expand", + GTK_SIGNAL_FUNC(cb_itemsignal), "expand"); + gtk_signal_connect (GTK_OBJECT(aitem), "collapse", + GTK_SIGNAL_FUNC(cb_itemsignal), "collapse"); + /* Add it to the parent tree */ + gtk_tree_append (GTK_TREE(real_tree), aitem); + + gtk_widget_show (aitem); + + gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data); + + fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen); + + if (dirp->smbc_type != SMBC_FILE && + dirp->smbc_type != SMBC_IPC_SHARE && + (strcmp(dirp->name, ".") != 0) && + (strcmp(dirp->name, "..") !=0)){ + + subtree = gtk_tree_new(); + gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree); + + gtk_signal_connect(GTK_OBJECT(subtree), "select_child", + GTK_SIGNAL_FUNC(cb_select_child), real_tree); + gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child", + GTK_SIGNAL_FUNC(cb_unselect_child), real_tree); + + } + + dirp = (struct smbc_dirent *) ((char *) dirp + dirlen); + err -= dirlen; + + } + + } + + smbc_closedir(dh); + + } + else if (strncmp(signame, "collapse", 8) == 0) { + GtkWidget *subtree = gtk_tree_new(); + + gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children); + + gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree); + + gtk_signal_connect (GTK_OBJECT(subtree), "select_child", + GTK_SIGNAL_FUNC(cb_select_child), real_tree); + gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child", + GTK_SIGNAL_FUNC(cb_unselect_child), real_tree); + + } + +} + +static void cb_selection_changed( GtkWidget *tree ) +{ + GList *i; + + g_print ("selection_change called for tree %p\n", tree); + g_print ("selected objects are:\n"); + + i = GTK_TREE_SELECTION(tree); + while (i){ + gchar *name; + GtkLabel *label; + GtkWidget *item; + + /* Get a GtkWidget pointer from the list node */ + item = GTK_WIDGET (i->data); + label = GTK_LABEL (GTK_BIN (item)->child); + gtk_label_get (label, &name); + g_print ("\t%s on level %d\n", name, GTK_TREE + (item->parent)->level); + i = i->next; + } +} + +/* + * Expand or collapse the whole network ... + */ +static void cb_wholenet(GtkWidget *item, gchar *signame) +{ + GtkWidget *real_tree, *aitem, *subtree; + gchar *name; + GtkLabel *label; + gint dh, err, dirlen; + char dirbuf[512]; + struct smbc_dirent *dirp; + + label = GTK_LABEL (GTK_BIN (item)->child); + gtk_label_get (label, &name); + g_print ("%s called for item %s->%p, level %d\n", signame, name, + item, GTK_TREE (item->parent)->level); + + real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */ + + if (strncmp(signame, "expand", 6) == 0) { /* Expand called */ + + if ((dh = smbc_opendir("smb://")) < 0) { /* Handle error */ + + g_print("cb_wholenet: Could not open dir smbc://, %s\n", + strerror(errno)); + + gtk_main_quit(); + + return; + + } + + while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, + sizeof(dirbuf))) != 0) { + + if (err < 0) { /* An error, report it */ + + g_print("cb_wholenet: Could not read dir smbc://, %s\n", + strerror(errno)); + + gtk_main_quit(); + + return; + + } + + dirp = (struct smbc_dirent *)dirbuf; + + while (err > 0) { + struct tree_data *my_data; + + dirlen = dirp->dirlen; + + my_data = make_tree_data(dirp->smbc_type, dirp->name); + + aitem = gtk_tree_item_new_with_label(dirp->name); + + /* Connect all GtkItem:: and GtkTreeItem:: signals */ + gtk_signal_connect (GTK_OBJECT(aitem), "select", + GTK_SIGNAL_FUNC(cb_itemsignal), "select"); + gtk_signal_connect (GTK_OBJECT(aitem), "deselect", + GTK_SIGNAL_FUNC(cb_itemsignal), "deselect"); + gtk_signal_connect (GTK_OBJECT(aitem), "toggle", + GTK_SIGNAL_FUNC(cb_itemsignal), "toggle"); + gtk_signal_connect (GTK_OBJECT(aitem), "expand", + GTK_SIGNAL_FUNC(cb_itemsignal), "expand"); + gtk_signal_connect (GTK_OBJECT(aitem), "collapse", + GTK_SIGNAL_FUNC(cb_itemsignal), "collapse"); + + gtk_tree_append (GTK_TREE(real_tree), aitem); + /* Show it - this can be done at any time */ + gtk_widget_show (aitem); + + gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data); + + fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen); + + subtree = gtk_tree_new(); + + gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree); + + gtk_signal_connect(GTK_OBJECT(subtree), "select_child", + GTK_SIGNAL_FUNC(cb_select_child), real_tree); + gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child", + GTK_SIGNAL_FUNC(cb_unselect_child), real_tree); + + dirp = (struct smbc_dirent *) ((char *) dirp + dirlen); + err -= dirlen; + + } + + } + + smbc_closedir(dh); + + } + else { /* Must be collapse ... FIXME ... */ + GtkWidget *subtree = gtk_tree_new(); + + gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children); + + gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree); + + gtk_signal_connect (GTK_OBJECT(subtree), "select_child", + GTK_SIGNAL_FUNC(cb_select_child), real_tree); + gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child", + GTK_SIGNAL_FUNC(cb_unselect_child), real_tree); + + + } + +} + +/* Should put up a dialog box to ask the user for username and password */ + +static void +auth_fn(const char *server, const char *share, + char *workgroup, int wgmaxlen, char *username, int unmaxlen, + char *password, int pwmaxlen) +{ + strncpy(username, "test", unmaxlen); + strncpy(password, "test", pwmaxlen); +} + +static char *col_titles[] = { + "Name", "Attributes", "Size", "Modification Date", +}; + +int main( int argc, + char *argv[] ) +{ + GtkWidget *window, *scrolled_win, *scrolled_win2, *tree; + GtkWidget *subtree, *item, *main_hbox, *r_pane, *l_pane; + gint err, dh; + gint i; + char dirbuf[512]; + struct smbc_dirent *dirp; + + gtk_init (&argc, &argv); + + /* Init the smbclient library */ + + err = smbc_init(auth_fn, 10); + + /* Print an error response ... */ + + if (err < 0) { + + fprintf(stderr, "smbc_init returned %s (%i)\nDo you have a ~/.smb/smb.conf file?\n", strerror(errno), errno); + exit(1); + + } + + /* a generic toplevel window */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name(window, "main browser window"); + gtk_signal_connect (GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + gtk_window_set_title(GTK_WINDOW(window), "The Linux Windows Network Browser"); + gtk_widget_set_usize(GTK_WIDGET(window), 750, -1); + gtk_container_set_border_width (GTK_CONTAINER(window), 5); + + gtk_widget_show (window); + + /* A container for the two panes ... */ + + main_hbox = gtk_hbox_new(FALSE, 1); + gtk_container_border_width(GTK_CONTAINER(main_hbox), 1); + gtk_container_add(GTK_CONTAINER(window), main_hbox); + + gtk_widget_show(main_hbox); + + l_pane = gtk_hpaned_new(); + gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size); + r_pane = gtk_hpaned_new(); + gtk_paned_gutter_size(GTK_PANED(r_pane), (GTK_PANED(r_pane))->handle_size); + gtk_container_add(GTK_CONTAINER(main_hbox), l_pane); + gtk_widget_show(l_pane); + + /* A generic scrolled window */ + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize (scrolled_win, 150, 200); + gtk_container_add (GTK_CONTAINER(l_pane), scrolled_win); + gtk_widget_show (scrolled_win); + + /* Another generic scrolled window */ + scrolled_win2 = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win2), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize (scrolled_win2, 150, 200); + gtk_paned_add2 (GTK_PANED(l_pane), scrolled_win2); + gtk_widget_show (scrolled_win2); + + /* Create the root tree */ + tree = gtk_tree_new(); + g_print ("root tree is %p\n", tree); + /* connect all GtkTree:: signals */ + gtk_signal_connect (GTK_OBJECT(tree), "select_child", + GTK_SIGNAL_FUNC(cb_select_child), tree); + gtk_signal_connect (GTK_OBJECT(tree), "unselect_child", + GTK_SIGNAL_FUNC(cb_unselect_child), tree); + gtk_signal_connect (GTK_OBJECT(tree), "selection_changed", + GTK_SIGNAL_FUNC(cb_selection_changed), tree); + /* Add it to the scrolled window */ + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win), + tree); + /* Set the selection mode */ + gtk_tree_set_selection_mode (GTK_TREE(tree), + GTK_SELECTION_MULTIPLE); + /* Show it */ + gtk_widget_show (tree); + + /* Now, create a clist and attach it to the second pane */ + + clist = gtk_clist_new_with_titles(4, col_titles); + + gtk_container_add (GTK_CONTAINER(scrolled_win2), clist); + + gtk_widget_show(clist); + + /* Now, build the top level display ... */ + + if ((dh = smbc_opendir("smb://")) < 0) { + + fprintf(stderr, "Could not list workgroups: smb://: %s\n", + strerror(errno)); + + exit(1); + + } + + /* Create a tree item for Whole Network */ + + item = gtk_tree_item_new_with_label ("Whole Network"); + /* Connect all GtkItem:: and GtkTreeItem:: signals */ + gtk_signal_connect (GTK_OBJECT(item), "select", + GTK_SIGNAL_FUNC(cb_itemsignal), "select"); + gtk_signal_connect (GTK_OBJECT(item), "deselect", + GTK_SIGNAL_FUNC(cb_itemsignal), "deselect"); + gtk_signal_connect (GTK_OBJECT(item), "toggle", + GTK_SIGNAL_FUNC(cb_itemsignal), "toggle"); + gtk_signal_connect (GTK_OBJECT(item), "expand", + GTK_SIGNAL_FUNC(cb_wholenet), "expand"); + gtk_signal_connect (GTK_OBJECT(item), "collapse", + GTK_SIGNAL_FUNC(cb_wholenet), "collapse"); + /* Add it to the parent tree */ + gtk_tree_append (GTK_TREE(tree), item); + /* Show it - this can be done at any time */ + gtk_widget_show (item); + + subtree = gtk_tree_new(); /* A subtree for Whole Network */ + + gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree); + + gtk_signal_connect (GTK_OBJECT(subtree), "select_child", + GTK_SIGNAL_FUNC(cb_select_child), tree); + gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child", + GTK_SIGNAL_FUNC(cb_unselect_child), tree); + + /* Now, get the items in smb:/// and add them to the tree */ + + while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, + sizeof(dirbuf))) != 0) { + + if (err < 0) { /* Handle the error */ + + fprintf(stderr, "Could not read directory for smbc:///: %s\n", + strerror(errno)); + + exit(1); + + } + + dirp = (struct smbc_dirent *)dirbuf; + + fprintf(stdout, "Dir len: %u\n", err); + + while (err > 0) { /* Extract each entry and make a sub-tree */ + struct tree_data *my_data; + int dirlen = dirp->dirlen; + + my_data = make_tree_data(dirp->smbc_type, dirp->name); + + item = gtk_tree_item_new_with_label(dirp->name); + /* Connect all GtkItem:: and GtkTreeItem:: signals */ + gtk_signal_connect (GTK_OBJECT(item), "select", + GTK_SIGNAL_FUNC(cb_itemsignal), "select"); + gtk_signal_connect (GTK_OBJECT(item), "deselect", + GTK_SIGNAL_FUNC(cb_itemsignal), "deselect"); + gtk_signal_connect (GTK_OBJECT(item), "toggle", + GTK_SIGNAL_FUNC(cb_itemsignal), "toggle"); + gtk_signal_connect (GTK_OBJECT(item), "expand", + GTK_SIGNAL_FUNC(cb_itemsignal), "expand"); + gtk_signal_connect (GTK_OBJECT(item), "collapse", + GTK_SIGNAL_FUNC(cb_itemsignal), "collapse"); + /* Add it to the parent tree */ + gtk_tree_append (GTK_TREE(tree), item); + /* Show it - this can be done at any time */ + gtk_widget_show (item); + + gtk_object_set_user_data(GTK_OBJECT(item), (gpointer)my_data); + + fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen); + + subtree = gtk_tree_new(); + + gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree); + + gtk_signal_connect (GTK_OBJECT(subtree), "select_child", + GTK_SIGNAL_FUNC(cb_select_child), tree); + gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child", + GTK_SIGNAL_FUNC(cb_unselect_child), tree); + + dirp = (struct smbc_dirent *) ((char *) dirp + dirlen); + err -= dirlen; + + } + + } + + smbc_closedir(dh); /* FIXME, check for error :-) */ + + /* Show the window and loop endlessly */ + gtk_main(); + return 0; +} +/* example-end */ diff --git a/examples/libsmbclient/wscript_build b/examples/libsmbclient/wscript_build new file mode 100644 index 0000000..c58a5b9 --- /dev/null +++ b/examples/libsmbclient/wscript_build @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +names = ['testsmbc', + 'testacl', + 'testacl2', + 'testacl3', + 'testbrowse', + 'testbrowse2', + 'testnotify', + 'teststat', + 'teststat2', + 'teststat3', + 'teststatvfs', + 'testfstatvfs', + 'testtruncate', + 'testchmod', + 'testutime', + 'testread', + 'testwrite', + 'testctx'] + +for name in names: + bld.SAMBA_BINARY(name, + source='%s.c' % name, + deps='popt smbclient', + install=False) diff --git a/examples/logon/genlogon/genlogon.pl b/examples/logon/genlogon/genlogon.pl new file mode 100644 index 0000000..4799ac8 --- /dev/null +++ b/examples/logon/genlogon/genlogon.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# +# genlogon.pl +# +# Perl script to generate user logon scripts on the fly, when users +# connect from a Windows client. This script should be called from smb.conf +# with the %U, %G and %L parameters. I.e: +# +# root preexec = genlogon.pl %U %G %L +# +# The script generated will perform +# the following: +# +# 1. Log the user connection to /var/log/samba/netlogon.log +# 2. Set the PC's time to the Linux server time (which is maintained +# daily to the National Institute of Standard's Atomic clock on the +# internet. +# 3. Connect the user's home drive to H: (H for Home). +# 4. Connect common drives that everyone uses. +# 5. Connect group-specific drives for certain user groups. +# 6. Connect user-specific drives for certain users. +# 7. Connect network printers. + +# Log client connection +#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +open LOG, ">>/var/log/samba/netlogon.log"; +print LOG "$mon/$mday/$year $hour:$min:$sec - User $ARGV[0] logged into $ARGV[1]\n"; +close LOG; + +# Start generating logon script +open LOGON, ">/shared/netlogon/$ARGV[0].bat"; +print LOGON "\@ECHO OFF\r\n"; + +# Connect shares just use by Software Development group +if ($ARGV[1] eq "SOFTDEV" || $ARGV[0] eq "softdev") +{ + print LOGON "NET USE M: \\\\$ARGV[2]\\SOURCE\r\n"; +} + +# Connect shares just use by Technical Support staff +if ($ARGV[1] eq "SUPPORT" || $ARGV[0] eq "support") +{ + print LOGON "NET USE S: \\\\$ARGV[2]\\SUPPORT\r\n"; +} + +# Connect shares just used by Administration staff +if ($ARGV[1] eq "ADMIN" || $ARGV[0] eq "admin") +{ + print LOGON "NET USE L: \\\\$ARGV[2]\\ADMIN\r\n"; + print LOGON "NET USE K: \\\\$ARGV[2]\\MKTING\r\n"; +} + +# Now connect Printers. We handle just two or three users a little +# differently, because they are the exceptions that have desktop +# printers on LPT1: - all other user's go to the LaserJet on the +# server. +if ($ARGV[0] eq 'jim' + || $ARGV[0] eq 'yvonne') +{ + print LOGON "NET UsE LPT2: \\\\$ARGV[2]\\LJET3\r\n"; + print LOGON "NET USE LPT3: \\\\$ARGV[2]\\FAXQ\r\n"; +} +else +{ + print LOGON "NET USE LPT1: \\\\$ARGV[2]\\LJET3\r\n"; + print LOGON "NET USE LPT3: \\\\$ARGV[2]\\FAXQ\r\n"; +} + +# All done! Close the output file. +close LOGON; diff --git a/examples/logon/mklogon/mklogon.conf b/examples/logon/mklogon/mklogon.conf new file mode 100644 index 0000000..9e585c5 --- /dev/null +++ b/examples/logon/mklogon/mklogon.conf @@ -0,0 +1,78 @@ +# Mapping should be kept in the form +# username(USER) or groupname(WEBUSERS) = driveletter (W:), samba share name (WEB) +# ie. user = W:,WEB or webusers = W:,WEB +# Problem found when testing, if there is a duplicate entry only the last one is used, +# not the first or both, another problem is that when testing I found a bug in Config::Simple, if you have a tab +# infront of your # on a comment it breaks ... +# logging = yes # Should Logging be enabled (YES,ON,1 or NO,OFF,0)(if not specified defaults to no) +# logdir = "/root/perl" # What is the base directory the logs should be stored. +# logfile = "userlist.txt" # What should the file be named. +# VERY IMPORTANT anything that has a "\" (backslash) in it ex. "C:\" MUST be changed to a double "\\" for +# it to be used in the script. ex. "C:\\" + +[global] +logging = yes +logdir = "/home/samba/netlogon" +logfile = "UserLogs.txt" +mkprofile = 1 +timesync = yes +sambaconf = "/etc/samba/smb.conf" +logtype = file + +# Change and uncomment the below value to force the servername, some clients occasionally +# have trouble picking up the right servername so it may need to be set. It CANNOT be left blank AND uncommented. +servername = "TIGER" + +[common] +public = P:, public +home = H:, /home + +[groupmap] +adm = R:, NETLOGON, Y:, ARCHIVES +teachers = S:, RECORDS, X:, SIS +plato = T:, PLATO +webpage = W:, WEB +hsoffice = N:, HSOFFICE, Q:, COMMON, X:, SIS +suoffice = N:, super, Q:, COMMON, X:, SIS +emoffice = N:, emOFFICE, Q:, COMMON, X:, SIS +tech = O:, utils +yearbook = Y:, yearbook + +[usermap] +rnance = G:, GHOST, I:, TTL, Y:, ARCHIVES, R:, NETLOGON, X:, SIS +lwatts = G:, GHOST, I:, TTL, Y:, ARCHIVES, R:, NETLOGON, X:, SIS +droot = U:, stuhomes +2007mbk = Y:, yearbook +2008mll = Y:, yearbook +2008jtj = Y:, yearbook +2007tja = Y:, yearbook +2007hms = Y:, yearbook +2006dpv = Y:, yearbook +2006jwb2 = Y:, yearbook +2007npd = Y:, yearbook +astewart = Y:, yearbook + + + +# Here is where things get confusing, you can assign a computer, or make a group of computers. +# The same context will go for ip address's as well, however you can also specify ip ranges, +# but I have not yet figured out how to do multiple ranges. +# Use the following examples for help. +# To define a single computer to do commands +# mymachinename = command1, command2 +# To define a group of computers to do commands +# mymachinegroup = machinename1, machinename2 +# [performcommands] +# mymachinegroup = command1,command2 +# iprangegroup1 = 10.1.2.1 - 10.1.3.1 + + + +[machines] + +[ip] +sixthemints = 10.1.5.201 - 10.1.5.215 + +[performcommands] +common = "XCOPY P:\\TYPEN32.INI C:\\WINDOWS\\ /Y \>NUL", "XCOPY P:\\ARPROGRAMS\\DBLOCATION\\\*\.\* C:\\WINDOWS\\ /Y \>NUL", "XCOPY P:\\EMACTIVITIES\\EMGAMESPREFS.INI C:\\WINDOWS\\ /Y \>NUL", "PATH\=\%PATH\%;p:\\PXPerl\parrot\\bin;p:\\PXPerl\\bin" +sixthemints = "start \\\\10.1.5.20\\printer" diff --git a/examples/logon/mklogon/mklogon.pl b/examples/logon/mklogon/mklogon.pl new file mode 100644 index 0000000..870abd1 --- /dev/null +++ b/examples/logon/mklogon/mklogon.pl @@ -0,0 +1,392 @@ +#!/usr/bin/perl -w + +# 05/01/2005 - 18:07:10 +# +# mklogon.pl - Login Script Generator +# Copyright (C) 2005 Ricky Nance +# ricky.nance@gmail.com +# http://www.weaubleau.k12.mo.us/~rnance/samba/mklogon.txt +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <http://www.gnu.org/licenses/>. +# + +# Version: 1.0 (Stable) +# Revised: 07/28/2005 + +# Comments... +# Working on logging to the system logs, Logs user activity, but not errors yet. + +use strict; +use Getopt::Long; + +eval { require Config::Simple; }; +if ($@) { + print("\n"); + print( "It appears as though you don't have the Config Simple perl module installed.\n" ); + print("The package is typically called 'Config::Simple' \n"); + print("and it needs to be installed, before you can use this utility\n"); + print("Most PERL installations will allow you to use a command like\n"); + print("\ncpan -i Config::Simple\n"); + print("from the command line while logged in as the root user.\n"); + print("\n"); + exit(1); +} + +# use Data::Dumper; #Used for debugging purposes + +# This variable should point to the external conf file, personally I would set +# it to /etc/samba/mklogon.conf +my $configfile; + +foreach my $dir ( ( '/etc', '/etc/samba', '/usr/local/samba/lib' ) ) { + if ( -e "$dir/mklogon.conf" ) { + $configfile = "$dir/mklogon.conf"; + last; + } +} + +# This section will come directly from the samba server. Basically it just makes the script easier to read. +my $getopts = GetOptions( + 'u|username=s' => \my $user, + 'm|machine=s' => \my $machine, + 's|servername=s' => \my $server, + 'o|ostype=s' => \my $os, + 'i|ip=s' => \my $ip, + 'd|date=s' => \my $smbdate, + 'h|help|?' => \my $help +); + +if ($help) { + help(); + exit(0); +} + +# We want the program to error out if its missing an argument. +if ( !defined($user) ) { error("username"); } +if ( !defined($machine) ) { error("machine name") } +if ( !defined($server) ) { error("server name") } +if ( !defined($os) ) { error("operating system") } +if ( !defined($ip) ) { error("ip address") } +if ( !defined($smbdate) ) { error("date") } + +# This section will be read from the external config file +my $cfg = new Config::Simple($configfile) or die "Could not find $configfile"; + +# Read this part from the samba config +my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time); +my $sambaconf = $cfg->param("global.sambaconf") or die "Couldn't find your samba config! \n"; +my $smbcfg = new Config::Simple( filename => $sambaconf, syntax => "ini" ); +my $smbprof = $smbcfg->param("profiles.path"); +my $smbnetlogdir = $smbcfg->param("netlogon.path"); +my $logging = lc( $cfg->param("global.logging") ); +my $mkprofile = lc( $cfg->param("global.mkprofile") ); +my $logdir = $cfg->param("global.logdir"); +my $logfile = $cfg->param("global.logfile"); +my $logs = "$logdir\/$logfile"; +my $logtype = $cfg->param("global.logtype"); +my $usermap = "usermap.$user"; +my $osmap = "os.$os"; +my @ostype = $cfg->param($osmap); +my @username = $cfg->param($usermap); +my $compname = $cfg->param( -block => "machines" ); +my $ipname = $cfg->param( -block => "ip" ); +my $timesync = $cfg->param("global.timesync"); +my $altserver = $cfg->param("global.servername"); +if ( defined($altserver) ) { $server = $altserver; } +$server = uc($server); + +# Lets start logging stuff if it is turned on in the config +if ( $logging =~ m/on|yes|1/i ) { + if ($logtype =~ m/file/i) { + print "----- Logging is turned on in the config. -----\n"; + print "----- Location of the logfile is \"$logs\" -----\n"; + open LOG, ">>$logs"; + printf LOG "Date: $smbdate Time: "; + printf LOG '%02d', $hour; + print LOG ":"; + printf LOG '%02d', $min; + print LOG "."; + printf LOG '%02d', $sec; + print LOG " -- User: $user - Machine: $machine - IP: $ip -- \n"; + close(LOG); + } elsif ($logtype =~ m/syslog|system/i){ + use Sys::Syslog; + my $alert = "User: $user Logged into $machine ($ip) at $hour:$min.$sec on $smbdate."; + openlog($0, 'cons', 'user'); + syslog('alert', $alert); + closelog(); + + } +} else { + print "----- Logging is turned off in the config. -----\n"; +} + +# If the user wants to make profiles with this script lets go +if ( defined($smbprof) ) { + if ( $mkprofile =~ m/on|yes|1/i ) { + print "----- Automatic making of user profiles is turned on in the config. ----- \n"; + ( my $login, my $pass, my $uid, my $gid ) = getpwnam($user) + or die "$user not in passwd file \n"; + $smbprof =~ s/\%U/$user/g; + my $dir2 = "$smbprof\/$user"; + print "$smbprof \n"; + print "$dir2 \n"; + if ( !-e $dir2 ) { + print "Creating " . $user . "'s profile with a uid of $uid\n"; + mkdir $smbprof; + mkdir $dir2; + chomp($user); +# chown $uid, $gid, $smbprof; + chown $uid, $gid, $dir2; + } else { + print $user . "'s profile already exists \n"; + } + } else { + print "----- Automatic making of user profiles is turned off in the config. ----- \n"; + } +} + +# Lets start making the batch files. +open LOGON, ">$smbnetlogdir\/$user.bat" or die "Unable to create userfile $smbnetlogdir\/$user.bat"; +print LOGON "\@ECHO OFF \r\n"; + +if ( $timesync =~ m/on|yes|1/i ) { + print LOGON "NET TIME /SET /YES \\\\$server \r\n"; +} else { + print "----- Time syncing to the client is turned off in the config. -----\n"; +} + +# Mapping from the common section +my $common = $cfg->param( -block => "common" ); +for my $key ( keys %$common ) { + drive_map( @{ $common->{$key} } ); +} + +my @perform_common = $cfg->param("performcommands.common"); +if ( defined( $perform_common[0] ) ) { + foreach (@perform_common) { + print LOGON "$_ \r\n"; + } +} + +# Map shares on a per user basis. +drive_map(@username); + +# Map shares based on the Operating System. +drive_map(@ostype); + +# Map shares only if they are in a group +# This line checks against the unix "groups" command, to see the secondary groups of a user. +my @usergroups = split( /\s/, do { open my $groups, "-|", groups => $user; <$groups> } ); +foreach (@usergroups) { + my $groupmap = "groupmap.$_"; + my @groupname = $cfg->param($groupmap); + drive_map(@groupname); +} + +#Here is where we check the machine name against the config... +for my $key ( keys %$compname ) { + my $test = $compname->{$key}; + if ( ref $test eq 'ARRAY' ) { + foreach (@$test) { + if ( $_ eq $machine ) { + my $performit = $cfg->param("performcommands.$key"); + if ( defined($performit) ) { + if ( ref $performit ) { + foreach (@$performit) { print LOGON "$_ \r\n"; } + } else { + print LOGON "$performit \r\n"; + } + } + } + } + } + elsif ( $test eq $machine ) { + my $performit = $cfg->param("performcommands.$key"); + if ( defined($performit) ) { + if ( ref $performit ) { + foreach (@$performit) { print LOGON "$_ \r\n"; } + } else { + print LOGON "$performit \r\n"; + } + } + } +} + +# Here is where we test the ip address against the client to see if they have "Special Mapping" +# A huge portion of the ip matching code was made by +# Carsten Schaub (rcsu in the #samba chan on freenode.net) + +my $val; +for my $key ( sort keys %$ipname ) { + if ( ref $ipname->{$key} eq 'ARRAY' ) { + foreach ( @{ $ipname->{$key} } ) { + getipval( $_, $key ); + } + } else { + getipval( $ipname->{$key}, $key ); + } +} + +sub getipval { + my ( $range, $rangename ) = @_; + if ( parse( $ip, ipmap($range) ) ) { + if ( $val eq 'true' ) { + my $performit = $cfg->param("performcommands.$rangename"); + if ( defined($performit) ) { + if ( ref $performit ) { + foreach (@$performit) { print LOGON "$_ \r\n"; } + } else { + print LOGON "$performit \r\n"; + } + } + } elsif ( $val eq 'false' ) { + } + } else { + } +} + +sub ipmap { + my $pattern = shift; + my ( $iprange, $iprange2, $ipmask ); + if ( $pattern =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/ ) { + # 1.1.1.1/3 notation + $iprange = pack( "U4", $1, $2, $3, $4 ); + $ipmask = pack( "U4", 0, 0, 0, 0 ); + my $numbits = $5; + for ( my $i = 0 ; $i < $numbits ; $i++ ) { + vec( $ipmask, int( $i / 8 ) * 8 + ( 8 - ( $i % 8 ) ) - 1, 1 ) = 1; + } + $iprange &= "$ipmask"; + } elsif ( $pattern =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/ ) { + # 1.1.1.1/255.255.255.255 notation + $iprange = pack( "U4", $1, $2, $3, $4 ); + $ipmask = pack( "U4", $5, $6, $7, $8 ); + $iprange &= "$ipmask"; + } elsif ( $pattern =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ ) { + # 1.1.1.1 notation + $iprange = pack( "U4", $1, $2, $3, $4 ); + $ipmask = pack( "U4", 255, 255, 255, 255 ); + } elsif ( $pattern =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s*\-\s*(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ ) { + # 1.1.1.1 - 2.2.2.2 notation + $iprange = pack( "U4", $1, $2, $3, $4 ); + $iprange2 = pack( "U4", $5, $6, $7, $8 ); + $ipmask = pack( "U4", 255, 255, 255, 255 ); + } else { + return; + } + return $iprange, $ipmask, $iprange2; +} + +sub parse { + my ( $origip, $ipbase, $ipmask, $iprange2 ) = @_; + $origip =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/; + $origip = pack( "U4", $1, $2, $3, $4 ); + if ( defined($iprange2) ) { + if ( $ipbase le $origip && $origip le $iprange2 ) { + return $val = 'true'; + } else { + return $val = 'false'; + } + } elsif ( ( "$origip" & "$ipmask" ) eq $ipbase ) { + return $val = 'true'; + } else { + return $val = 'false'; + } +} + +# This sub will distinguish the drive mappings +sub drive_map { + my @data = @_; + for ( my $i = 0 ; $i < scalar(@data) ; ) { + if ( $data[$i] =~ m/^[a-z]\:$/i ) { + my $driveletter = $data[$i]; + $i++; + my $sharename = $data[$i]; + $i++; + if ( $sharename eq '/home' ) { + print LOGON uc("NET USE $driveletter \\\\$server\\$user \/Y \r\n"); + } else { + print LOGON + uc("NET USE $driveletter \\\\$server\\$sharename \/Y \r\n"); + } + } else { + print LOGON uc("$data[$i] \r\n"); + $i++; + } + } +} + +close(LOGON); + +sub error { + my $var = shift(@_); + help(); + print "\n\tCritical!!! \n\n\tNo $var specified\n\n\tYou must specify a $var.\n\n"; + exit(0); +} + +sub help { + + print << "EOF" ; + + Usage: $0 [options] + + Options: + + -h,--help This help screen. + + -u,--username The name of the user from the samba server. + + -m,--machinename The name of the client connecting to the server. + + -s,--server The name of the server this script is running in. + + -o,--os The clients OS -- Windows 95/98/ME (Win95), Windows NT (WinNT), + Windows 2000 (Win2K), Windows XP (WinXP), and Windows 2003 + (Win2K3). Anything else will be known as ``UNKNOWN'' + That snippet is directly from man smb.conf. + + -i,--ip The clients IP address. + + -d,--date Time and Date returned from the samba server. + + + + --IMPORTANT-- + + + All options MUST be specified. + + The mklogon.conf file MUST be located in /etc, /etc/samba, or + /usr/local/samba/lib. + + To use this file from the command line: + $0 -u User -m machine -s servername -o ostype -i X.X.X.X -d MM/DD/YY + + To use this file from the samba server add these lines to your /etc/samba/smb.conf: + + + This line goes in the [global] section + login script = %U.bat + + This line should be at the end of the [netlogon] section. + root preexec = /path/to/mklogon.pl -u %U -m %m -s %L -o %a -i %I -d %t + + +EOF + + print "\n\n"; + +} diff --git a/examples/logon/ntlogon/README b/examples/logon/ntlogon/README new file mode 100644 index 0000000..da52562 --- /dev/null +++ b/examples/logon/ntlogon/README @@ -0,0 +1,160 @@ +ntlogon.py v0.8b Copyright 2002 by Timothy (rhacer) Grant +This programme is released under the terms of the GNU Public License +This programme has NO WARRANTY of any kind, use at your own risk. + +=================== +CHANGES SINCE v0.7b +=================== +included patch that made machine name %m a macro substitution value. +Thanks to: Nick Lopez <kimo_sabe@atdot.org> + +================== +CHANGES SINCE v0.6 +================== +PLEASE NOT THAT I AM CONSIDERING THIS A BETA UNTIL I GET SOME FEEDBACK +FROM USERS ON WHETHER THE MACRO FEATURE WORKS FOR THEM. + +added the ability to define substitution macros: see the usage section + +removed the large docstring from the file and moved the information to +the USAGE section of this file + +cleaned up the code and made more flexible + +improved the code comments + +================== +CHANGES SINCE v0.5 +================== +added a -v --version switch + +added a --pause switch which will put a pause statement between each +non-blank line of the script. + +=============== +A PERSONAL NOTE +=============== +When I originally posted v0.5 on Freshmeat, I really expected *some* +feedback. To date this little script has been downloaded over 700 times, but +absolutely nobody has sent me an e-mail to tell me if it is useful, or if +it is absolutely the stupidest waste of bandwidth they have ever seen. +I'd really love to know if even one person other than me and the other techs +here at Avalon have found it useful. + +Thanks. + rhacer (rhacer@craigelachie.org) + +September 27, 2000 +Thanks to those that did respond to my plea! I'd still love to hear from +any other users! + +============ +INTRODUCTION +============ +As my experience with Linux and Samba increased, I had no trouble whipping up +a custom Perl, Python or Bash script to create Samba Logon Scripts, but I +noticed that I changed things from place to place, and that my users had *no* +chance of ever figuring out how to modify those scripts themselves. + +In an attempt to create a company wide standard that both my co-workers and my +customers could *easily* modify I hit upon the scheme I used here. + +I settled on an INI file feel, because most who have experience with Win boxes +have some concept of INI files. + +============ +INSTALLATION +============ +The distribution archive contains three files: + +README This file +ntlogon.py The actual Python script (place in /usr/local/samba/bin) +ntlogon.conf A sample configuration file (place in /etc) + +This script was created using Python v1.5.2, and I believe it uses only +standard libraries. + +Your smb.conf file needs to contain a netlogon section similar to the +following (These settings *are not* normal on a RH box. These settings +are all based on the excellent book that I learned Samba from: Samba +Integrating Unix and Windows by John D. Blair. It is somewhat out of +date now, but that's the history of the strange file locations): + +[netlogon] + path = /usr/local/samba/netlogon + writeable = no + guest ok = no + root preexec = /usr/local/samba/bin/ntlogon --user=%U --os=%m + root postexec = rm /usr/local/samba/netlogon/%U.bat + +====== +USAGE +====== +PLEASE SEE NTLOGON.CONF FOR A DETAILED CONFIGURATION EXAMPLE + +This programme will build a Windows NT logon script for users connecting +to a Samba server. Samba macros that are currently understood: + + %U user name + %G group name + %a machine architecture + %m machine netbios name + +This programme reads a configuration that looks strikingly similar to both +the Samba configuration file, and a DOS "boot menu" AUTOEXEC.BAT file. + +The default file name is /etc/ntlogon.conf (though I really think it ought +to be called ntlogon.batch!) You may change the filename by using the -f +or --templatefile startup option. + +The default netlogon directory is /usr/local/samba/netlogon though this +can be changed with the -d or --dir startup option. + +The default batch file name generated is username.bat if no username is +specified the default value is logon.bat (e.g., if --user=fred is specified +on the command line then the logon script generated will be stored in +fred.bat) + +Use the --debug option to print the logon script to screen instead of the +output file + +Use the --pause option to place a pause statement between each line of the +script to assist in debugging a logon script. + +The file is divided into sections that have headers in square brackets + +[Global] +[User-username] +[Group-groupname] +[OS-osname] + +The file may also contain user defined substitution macros. They are +defined by placing the macro name on the left side of an equal sign, +and the substitution text on the right side of the equal sign. They +are also case sensitive: + +MAINDRIVE = G: +USERDRIVE = U: +SERVERNAME = myservername + +They are referenced by prepending a "%" sign to the variable name: + +NET USE %MAINDRIVE \\\\servername\\mainshare /YES +NET USE %USERDRIVE \\\\%SERVERNAME\\usershare /YES + +============== +SPECIAL THANKS +============== +Nick Lopez <kimo_sabe@atdot.org> for the net bios name patch. + +=================== +CONTACT INFORMATION +=================== +Author : Timothy (rhacer) Grant + +I can be reached at tjg@craigelachie.org +ntlogon website www.craigelachie.org/rhacer/ntlogon + +Please feel free to contact me with any suggestions, improvements, bugs you +might find. + diff --git a/examples/logon/ntlogon/ntlogon.conf b/examples/logon/ntlogon/ntlogon.conf new file mode 100644 index 0000000..e1573a6 --- /dev/null +++ b/examples/logon/ntlogon/ntlogon.conf @@ -0,0 +1,44 @@ +# Everything in the Global section applies to all users logging on to the +# network +[Global] + +#Some substitution macro definitions +MAINDRIVE = G: +USERDRIVE = U: +SERVERNAME = myservername + +@ECHO "Welcome to our network!!!" +NET TIME \\servername /SET /YES +NET USE %MAINDRIVE \\%SERVERNAME\globalshare /YES + +# Map the private user area in the global section so we don't have to +# create individual user entries for each user! +NET USE %USERDRIVE \\servername\%U /YES + +# Group entries, User entries and OS entries each start with the +# keyword followed by a dash followed by--appropriately enough the Group +# name, the User name, or the OS name. +[Group-admin] +@ECHO "Welcome administrators!" +NET USE G: \\servername\adminshare1 /YES +NET USE I: \\servername\adminshare2 /YES + +[Group-peons] +@ECHO "Be grateful we let you use computers!" +NET USE G: \\servername\peonshare1 /YES + +[Group-hackers] +@ECHO "What can I do for you today great one?" +NET USE G: \\servername\hackershare1 /YES +NET USE I: \\servername\adminshare2 /YES + +[User-fred] +@ECHO "Hello there Fred!" +NET USE F: \\servername\fredsspecialshare /YES + +[OS-WfWg] +@ECHO "Time to upgrade isn't it?" + +# End configuration file + +X = Will this break? diff --git a/examples/logon/ntlogon/ntlogon.py b/examples/logon/ntlogon/ntlogon.py new file mode 100755 index 0000000..7213012 --- /dev/null +++ b/examples/logon/ntlogon/ntlogon.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python3 +""" +ntlogon.py written by Timothy (rhacer) Grant + +Copyright 1999 - 2002 by Timothy Grant + +is distributed under the terms of the GNU Public License. + +The format for the configuration file is as follows: + +While there is some room for confusion, we attempt to process things in +order of specificity: Global first, Group second, User third, OS Type +forth. This order can be debated forever, but it seems to make the most +sense. + +# Everything in the Global section applies to all users logging on to the +# network +[Global] +@ECHO "Welcome to our network!!!" +NET TIME \\\\servername /SET /YES +NET USE F: \\\\servername\\globalshare /YES + +# Map the private user area in the global section so we don't have to +# create individual user entries for each user! +NET USE U: \\\\servername\\%U /YES + +# Group entries, User entries and OS entries each start with the +# keyword followed by a dash followed by--appropriately enough the Group +# name, the User name, or the OS name. +[Group-admin] +@ECHO "Welcome administrators!" +NET USE G: \\\\servername\\adminshare1 /YES +NET USE I: \\\\servername\\adminshare2 /YES + +[Group-peons] +@ECHO "Be grateful we let you use computers!" +NET USE G: \\\\servername\\peonshare1 /YES + +[Group-hackers] +@ECHO "What can I do for you today great one?" +NET USE G: \\\\servername\\hackershare1 /YES +NET USE I: \\\\servername\\adminshare2 /YES + +[User-fred] +@ECHO "Hello there Fred!" +NET USE F: \\\\servername\\fredsspecialshare /YES + +[OS-WfWg] +@ECHO "Time to upgrade it?" + +# End configuration file + +usage: ntlogon [-g | --group=groupname] + [-u | --user=username] + [-o | --os=osname] + [-m | --machine=netbiosname] + [-f | --templatefile=filename] + [-d | --dir=netlogon directory] + [-v | --version] + [-h | --help] + [--pause] + [--debug] +""" +# +#" This quote mark is an artifact of the inability of my editor to +# correctly colour code anything after the triple-quoted docstring. +# if your editor does not have this flaw, feel free to remove it. + + +import sys +import getopt +import re +import string +import os + +version = "ntlogon.py v0.8" + +def buildScript(buf, sections, group, user, ostype, machine, debug, pause): + """ + buildScript() Takes the contents of the template file and builds + a DOS batch file to be executed as an NT logon script. It does this + by determining which sections of the configuration file should be included + and creating a list object that contains each line contained in each + included section. The list object is then returned to the calling + routine. + + All comments (#) are removed. A REM is inserted to show + which section of the configuration file each line comes from. + We leave blanklines as they are sometimes useful for debugging + + We also replace all of the Samba macros (e.g., %U, %G, %a, %m) with their + expanded versions which have been passed to us by smbd + """ + hdrstring = '' + script = [] + + # + # These are the Samba macros that we currently know about. + # any user defined macros will also be added to this dictionary. + # We do not store the % sign as part of the macro name. + # The replace routine will prepend the % sign to all possible + # replacements. + # + macros = { + 'U': user, + 'G': group, + 'a': ostype, + 'm': machine + } + + # + # Process each section defined in the list sections + # + for s in sections: + # print 'searching for: ' + s + + idx = 0 + + while idx < len(buf): + ln = buf[idx] + + # + # We need to set up a regex for each possible section we + # know about. This is slightly complicated due to the fact + # that section headers contain user defined text. + # + if s == 'Global': + hdrstring = r'\[ *' + s + r' *\]' + elif s == 'Group': + hdrstring = r'\[ *' + s + ' *- *' + group + r' *\]' + elif s == 'User': + hdrstring = r'\[ *' + s + ' *- *' + user + r' *\]' + elif s == 'OS': + hdrstring = r'\[ *' + s + ' *- *' + ostype + r' *\]' + elif s == 'Machine': + hdrstring = r'\[ *' + s + ' *- *' + machine + r' *\]' + + # + # See if we have found a section header + # + if re.search(r'(?i)' + hdrstring, ln): + idx = idx + 1 # increment the counter to move to the next + # line. + + x = re.match(r'([^#\r\n]*)', ln) # Determine the section + # name and strip out CR/LF + # and comment information + + if debug: + print 'rem ' + x.group(1) + ' commands' + else: + # create the rem at the beginning of each section of the + # logon script. + script.append('rem ' + x.group(1) + ' commands') + + # + # process each line until we have found another section + # header + # + while not re.search(r'.*\[.*\].*', buf[idx]): + + # + # strip comments and line endings + # + x = re.match(r'([^#\r\n]*)', buf[idx]) + + if string.strip(x.group(1)) != '' : + # if there is still content after stripping comments and + # line endings then this is a line to process + + line = x.group(1) + + # + # Check to see if this is a macro definition line + # + vardef = re.match(r'(.*)=(.*)', line) + + if vardef: + varname = string.strip(vardef.group(1)) # Strip leading and + varsub = string.strip(vardef.group(2)) # and trailing spaces + + if varname == '': + print "Error: No substitution name specified line: %d" % idx + sys.exit(1) + + if varsub == '': + print "Error: No substitution text provided line: %d" % idx + sys.exit(1) + + if varname in macros: + print "Warning: macro %s redefined line: %d" % (varname, idx) + + macros[varname] = varsub + idx = idx + 1 + continue + + # + # Replace all the macros that we currently + # know about. + # + # Iterate over the dictionary that contains all known + # macro substitutions. + # + # We test for a macro name by prepending % to each dictionary + # key. + # + for varname in macros.keys(): + line = re.sub(r'%' + varname + r'(\W)', + macros[varname] + r'\1', line) + + if debug: + print line + if pause: + print 'pause' + else: + script.append(line) + + idx = idx + 1 + + if idx == len(buf): + break # if we have reached the end of the file + # stop processing. + + idx = idx + 1 # increment the line counter + + if debug: + print '' + else: + script.append('') + + return script + +# End buildScript() + +def run(): + """ + run() everything starts here. The main routine reads the command line + arguments, opens and reads the configuration file. + """ + configfile = '/etc/ntlogon.conf' # Default configuration file + group = '' # Default group + user = '' # Default user + ostype = '' # Default os + machine = '' # Default machine type + outfile = 'logon.bat' # Default batch file name + # this file name WILL take on the form + # username.bat if a username is specified + debug = 0 # Default debugging mode + pause = 0 # Default pause mode + outdir = '/usr/local/samba/netlogon/' # Default netlogon directory + + sections = ['Global', 'Machine', 'OS', 'Group', 'User'] # Currently supported + # configuration file + # sections + + options, args = getopt.getopt(sys.argv[1:], 'd:f:g:ho:u:m:v', + ['templatefile=', + 'group=', + 'help', + 'os=', + 'user=', + 'machine=', + 'dir=', + 'version', + 'pause', + 'debug']) + + # + # Process the command line arguments + # + for i in options: + # template file to process + if (i[0] == '-f') or (i[0] == '--templatefile'): + configfile = i[1] + # print 'configfile = ' + configfile + + # define the group to be used + elif (i[0] == '-g') or (i[0] == '--group'): + group = i[1] + # print 'group = ' + group + + # define the os type + elif (i[0] == '-o') or (i[0] == '--os'): + ostype = i[1] + # print 'os = ' + os + + # define the user + elif (i[0] == '-u') or (i[0] == '--user'): + user = i[1] + outfile = user + '.bat' # Setup the output file name + # print 'user = ' + user + + # define the machine + elif (i[0] == '-m') or (i[0] == '--machine'): + machine = i[1] + + # define the netlogon directory + elif (i[0] == '-d') or (i[0] == '--dir'): + outdir = i[1] + # print 'outdir = ' + outdir + + # if we are asked to turn on debug info, do so. + elif (i[0] == '--debug'): + debug = 1 + # print 'debug = ' + debug + + # if we are asked to turn on the automatic pause functionality, do so + elif (i[0] == '--pause'): + pause = 1 + # print 'pause = ' + pause + + # if we are asked for the version number, print it. + elif (i[0] == '-v') or (i[0] == '--version'): + print version + sys.exit(0) + + # if we are asked for help print the docstring. + elif (i[0] == '-h') or (i[0] == '--help'): + print __doc__ + sys.exit(0) + + # + # open the configuration file + # + try: + iFile = open(configfile, 'r') + except IOError: + print 'Unable to open configuration file: ' + configfile + sys.exit(1) + + # + # open the output file + # + if not debug: + try: + oFile = open(outdir + outfile, 'w') + except IOError: + print 'Unable to open logon script file: ' + outdir + outfile + sys.exit(1) + + buf = iFile.readlines() # read in the entire configuration file + + # + # call the script building routine + # + script = buildScript(buf, sections, group, user, ostype, machine, debug, pause) + + # + # write out the script file + # + if not debug: + for ln in script: + oFile.write(ln + '\r\n') + if pause: + if string.strip(ln) != '': # Because whitespace + oFile.write('pause' + '\r\n') # is a useful tool, we + # don't put pauses after + # an empty line. + + +# End run() + +# +# immediate-mode commands, for drag-and-drop or execfile() execution +# +if __name__ == '__main__': + run() +else: + print "Module ntlogon.py imported." + print "To run, type: ntlogon.run()" + print "To reload after changes to the source, type: reload(ntlogon)" + +# +# End NTLogon.py +# diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl new file mode 100755 index 0000000..fc24811 --- /dev/null +++ b/examples/misc/adssearch.pl @@ -0,0 +1,1897 @@ +#!/usr/bin/perl -w +# +# adssearch.pl - query an Active Directory server and +# display objects in a human readable format +# +# Copyright (C) Guenther Deschner <gd@samba.org> 2003-2008 +# +# TODO: add range retrieval +# write sddl-converter, decode userParameters +# apparently only win2k3 allows simple-binds with machine-accounts. +# make sasl support independent from Authen::SASL::Cyrus v >0.11 +use strict; + +use Net::LDAP; +use Net::LDAP::Control; +use Net::LDAP::Constant qw(LDAP_REFERRAL); +use Convert::ASN1; +use Time::Local; +use POSIX qw(strftime); +use Getopt::Long; + +my $have_sasl; +my $works_sasl; +my $pref_version; +BEGIN { + my $class = 'Authen::SASL'; + $pref_version = "0.32"; + if ( eval "require $class;" ) { + $have_sasl = 1; + } + if ( eval "Net::LDAP->VERSION($pref_version);" ) { + $works_sasl = 1; + } +} + +# users may set defaults here +my $base = ""; +my $binddn = ""; +my $password = ""; +my $server = ""; +my $rebind_url; + + +my $tdbdump = "/usr/bin/tdbdump"; +my $ntdbdump = "/usr/bin/ntdbdump"; +my $testparm = "/usr/bin/testparm"; +my $net = "/usr/bin/net"; +my $dig = "/usr/bin/dig"; +my $nmblookup = "/usr/bin/nmblookup"; +my $secrets_tdb = "/etc/samba/secrets.tdb"; +my $secrets_ntdb = "/etc/samba/secrets.ntdb"; +my $klist = "/usr/bin/klist"; +my $kinit = "/usr/bin/kinit"; +my $workgroup = ""; +my $machine = ""; +my $realm = ""; + +# parse input +my ( + $opt_asq, + $opt_base, + $opt_binddn, + $opt_debug, + $opt_display_extendeddn, + $opt_display_metadata, + $opt_display_raw, + $opt_domain_scope, + $opt_dump_rootdse, + $opt_dump_schema, + $opt_dump_wknguid, + $opt_fastbind, + $opt_help, + $opt_host, + $opt_machine, + $opt_notify, + $opt_notify_nodiffs, + $opt_paging, + $opt_password, + $opt_port, + $opt_realm, + $opt_saslmech, + $opt_search_opt, + $opt_scope, + $opt_simpleauth, + $opt_starttls, + $opt_user, + $opt_verbose, + $opt_workgroup, +); + +GetOptions( + 'asq=s' => \$opt_asq, + 'base|b=s' => \$opt_base, + 'D|DN=s' => \$opt_binddn, + 'debug=i' => \$opt_debug, + 'domain_scope' => \$opt_domain_scope, + 'extendeddn|e:i' => \$opt_display_extendeddn, + 'fastbind' => \$opt_fastbind, + 'help' => \$opt_help, + 'host|h=s' => \$opt_host, + 'machine|P' => \$opt_machine, + 'metadata|m' => \$opt_display_metadata, + 'nodiffs' => \$opt_notify_nodiffs, + 'notify|n' => \$opt_notify, + 'paging:i' => \$opt_paging, + 'password|w=s' => \$opt_password, + 'port=i' => \$opt_port, + 'rawdisplay' => \$opt_display_raw, + 'realm|R=s' => \$opt_realm, + 'rootDSE' => \$opt_dump_rootdse, + 'saslmech|Y=s' => \$opt_saslmech, + 'schema|c' => \$opt_dump_schema, + 'scope|s=s' => \$opt_scope, + 'searchopt:i' => \$opt_search_opt, + 'simpleauth|x' => \$opt_simpleauth, + 'tls|Z' => \$opt_starttls, + 'user|U=s' => \$opt_user, + 'verbose|v' => \$opt_verbose, + 'wknguid' => \$opt_dump_wknguid, + 'workgroup|k=s' => \$opt_workgroup, + ); + + +if (!@ARGV && !$opt_dump_schema && !$opt_dump_rootdse && !$opt_notify || $opt_help) { + usage(); + exit 1; +} + +if ($opt_fastbind && !$opt_simpleauth) { + printf("LDAP fast bind can only be performed with simple binds\n"); + exit 1; +} + +if ($opt_notify) { + $opt_paging = undef; +} + +# get the query +my $query = shift; +my @attrs = @ARGV; + +# some global vars +my $filter = ""; +my ($dse, $uri); +my ($attr, $value); +my (@ctrls, @ctrls_s); +my ($ctl_paged, $cookie); +my ($page_count, $total_entry_count); +my ($sasl_hd, $async_ldap_hd, $sync_ldap_hd); +my ($mesg, $usn); +my (%entry_store); +my $async_search; + +# fixed values and vars +my $set = "X"; +my $unset = "-"; +my $tabsize = "\t\t\t"; + +# get defaults +my $scope = $opt_scope || "sub"; +my $port = $opt_port; + +my %ads_controls = ( +"LDAP_SERVER_NOTIFICATION_OID" => "1.2.840.113556.1.4.528", +"LDAP_SERVER_EXTENDED_DN_OID" => "1.2.840.113556.1.4.529", +"LDAP_PAGED_RESULT_OID_STRING" => "1.2.840.113556.1.4.319", +"LDAP_SERVER_SD_FLAGS_OID" => "1.2.840.113556.1.4.801", +"LDAP_SERVER_SORT_OID" => "1.2.840.113556.1.4.473", +"LDAP_SERVER_RESP_SORT_OID" => "1.2.840.113556.1.4.474", +"LDAP_CONTROL_VLVREQUEST" => "2.16.840.1.113730.3.4.9", +"LDAP_CONTROL_VLVRESPONSE" => "2.16.840.1.113730.3.4.10", +"LDAP_SERVER_RANGE_RETRIEVAL" => "1.2.840.113556.1.4.802", #unsure +"LDAP_SERVER_SHOW_DELETED_OID" => "1.2.840.113556.1.4.417", +"LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID" => "1.2.840.113556.1.4.521", +"LDAP_SERVER_LAZY_COMMIT_OID" => "1.2.840.113556.1.4.619", +"LDAP_SERVER_TREE_DELETE_OID" => "1.2.840.113556.1.4.805", +"LDAP_SERVER_DIRSYNC_OID" => "1.2.840.113556.1.4.841", +"LDAP_SERVER_VERIFY_NAME_OID" => "1.2.840.113556.1.4.1338", +"LDAP_SERVER_DOMAIN_SCOPE_OID" => "1.2.840.113556.1.4.1339", +"LDAP_SERVER_SEARCH_OPTIONS_OID" => "1.2.840.113556.1.4.1340", +"LDAP_SERVER_PERMISSIVE_MODIFY_OID" => "1.2.840.113556.1.4.1413", +"LDAP_SERVER_ASQ_OID" => "1.2.840.113556.1.4.1504", +"NONE (Get stats control)" => "1.2.840.113556.1.4.970", +"LDAP_SERVER_QUOTA_CONTROL_OID" => "1.2.840.113556.1.4.1852", +"LDAP_SERVER_SHUTDOWN_NOTIFY_OID" => "1.2.840.113556.1.4.1907", +); + +my %ads_capabilities = ( +"LDAP_CAP_ACTIVE_DIRECTORY_OID" => "1.2.840.113556.1.4.800", +"LDAP_CAP_ACTIVE_DIRECTORY_V51_OID" => "1.2.840.113556.1.4.1670", +"LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID" => "1.2.840.113556.1.4.1791", +); + +my %ads_extensions = ( +"LDAP_START_TLS_OID" => "1.3.6.1.4.1.1466.20037", +"LDAP_TTL_EXTENDED_OP_OID" => "1.3.6.1.4.1.1466.101.119.1", +"LDAP_SERVER_FAST_BIND_OID" => "1.2.840.113556.1.4.1781", +"NONE (TTL refresh extended op)" => "1.3.6.1.4.1.1466.101.119.1", +); + +my %ads_matching_rules = ( +"LDAP_MATCHING_RULE_BIT_AND" => "1.2.840.113556.1.4.803", +"LDAP_MATCHING_RULE_BIT_OR" => "1.2.840.113556.1.4.804", +); + +my %wknguids = ( +"WELL_KNOWN_GUID_COMPUTERS" => "AA312825768811D1ADED00C04FD8D5CD", +"WELL_KNOWN_GUID_DOMAIN_CONTROLLERS" => "A361B2FFFFD211D1AA4B00C04FD7D83A", +"WELL_KNOWN_GUID_SYSTEM" => "AB1D30F3768811D1ADED00C04FD8D5CD", +"WELL_KNOWN_GUID_USERS" => "A9D1CA15768811D1ADED00C04FD8D5CD", +); + +my %ads_systemflags = ( +"FLAG_DONT_REPLICATE" => 0x00000001, # 1 +"FLAG_REPLICATE_TO_GC" => 0x00000002, # 2 +"FLAG_ATTRIBUTE_CONSTRUCT" => 0x00000004, # 4 +"FLAG_CATEGORY_1_OBJECT" => 0x00000010, # 16 +"FLAG_DELETE_WITHOUT_TOMBSTONE" => 0x02000000, # 33554432 +"FLAG_DOMAIN_DISALLOW_MOVE" => 0x04000000, # 67108864 +"FLAG_DOMAIN_DISALLOW_RENAME" => 0x08000000, # 134217728 +#"FLAG_CONFIG_CAN_MOVE_RESTRICTED" => 0x10000000, # 268435456 # only setable on creation +#"FLAG_CONFIG_CAN_MOVE" => 0x20000000, # 536870912 # only setable on creation +#"FLAG_CONFIG_CAN_RENAME" => 0x40000000, # 1073741824 # only setable on creation +"FLAG_DISALLOW_DELETE" => 0x80000000, # 2147483648 +); + +my %ads_mixed_domain = ( +"NATIVE_LEVEL_DOMAIN" => 0, +"MIXED_LEVEL_DOMAIN" => 1, +); + +my %ads_ds_func = ( +"DS_BEHAVIOR_WIN2000" => 0, # untested +"DS_BEHAVIOR_WIN2003" => 2, +"DS_BEHAVIOR_WIN2008" => 3, +); + +my %ads_instance_type = ( +"DS_INSTANCETYPE_IS_NC_HEAD" => 0x1, +"IT_WRITE" => 0x4, +"IT_NC_ABOVE" => 0x8, +); + +my %ads_uacc = ( + "ACCOUNT_NEVER_EXPIRES" => 0x000000, # 0 + "ACCOUNT_OK" => 0x800000, # 8388608 + "ACCOUNT_LOCKED_OUT" => 0x800010, # 8388624 +); + +my %ads_enctypes = ( + "DES-CBC-CRC" => 0x01, + "DES-CBC-MD5" => 0x02, + "RC4_HMAC_MD5" => 0x04, + "AES128_CTS_HMAC_SHA1_96" => 0x08, + "AES128_CTS_HMAC_SHA1_128" => 0x10, +); + +my %ads_gpoptions = ( + "GPOPTIONS_INHERIT" => 0, + "GPOPTIONS_BLOCK_INHERITANCE" => 1, +); + +my %ads_gplink_opts = ( + "GPLINK_OPT_NONE" => 0, + "GPLINK_OPT_DISABLED" => 1, + "GPLINK_OPT_ENFORCED" => 2, +); + +my %ads_gpflags = ( + "GPFLAGS_ALL_ENABLED" => 0, + "GPFLAGS_USER_SETTINGS_DISABLED" => 1, + "GPFLAGS_MACHINE_SETTINGS_DISABLED" => 2, + "GPFLAGS_ALL_DISABLED" => 3, +); + +my %ads_serverstate = ( + "SERVER_ENABLED" => 1, + "SERVER_DISABLED" => 2, +); + +my %ads_sdeffective = ( + "OWNER_SECURITY_INFORMATION" => 0x01, + "DACL_SECURITY_INFORMATION" => 0x04, + "SACL_SECURITY_INFORMATION" => 0x10, +); + +my %ads_trustattrs = ( + "TRUST_ATTRIBUTE_NON_TRANSITIVE" => 0x00000001, + "TRUST_ATTRIBUTE_UPLEVEL_ONLY" => 0x00000002, + "TRUST_ATTRIBUTE_QUARANTINED_DOMAIN" => 0x00000004, + "TRUST_ATTRIBUTE_FOREST_TRANSITIVE" => 0x00000008, + "TRUST_ATTRIBUTE_CROSS_ORGANIZATION" => 0x00000010, + "TRUST_ATTRIBUTE_WITHIN_FOREST" => 0x00000020, + "TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL" => 0x00000040, + "TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION" => 0x00000080, + "TRUST_ATTRIBUTE_CROSS_ORGANIZATION_NO_TGT_DELEGATION" => 0x00000200, + "TRUST_ATTRIBUTE_PIM_TRUST" => 0x00000400, + "TRUST_ATTRIBUTE_CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION" => 0x00000800, +); + +my %ads_trustdirection = ( + "TRUST_DIRECTION_INBOUND" => 1, + "TRUST_DIRECTION_OUTBOUND" => 2, + "TRUST_DIRECTION_BIDIRECTIONAL" => 3, +); + +my %ads_trusttype = ( + "TRUST_TYPE_DOWNLEVEL" => 1, + "TRUST_TYPE_UPLEVEL" => 2, + "TRUST_TYPE_KERBEROS" => 3, + "TRUST_TYPE_DCE" => 4, +); + +my %ads_pwdproperties = ( + "DOMAIN_PASSWORD_COMPLEX" => 1, + "DOMAIN_PASSWORD_NO_ANON_CHANGE" => 2, + "DOMAIN_PASSWORD_NO_CLEAR_CHANGE" => 4, + "DOMAIN_LOCKOUT_ADMINS" => 8, + "DOMAIN_PASSWORD_STORE_CLEARTEXT" => 16, + "DOMAIN_REFUSE_PASSWORD_CHANGE" => 32, +); + +my %ads_uascompat = ( + "LANMAN_USER_ACCOUNT_SYSTEM_NOLIMITS" => 0, + "LANMAN_USER_ACCOUNT_SYSTEM_COMPAT" => 1, +); + +my %ads_frstypes = ( + "REPLICA_SET_SYSVOL" => 2, # unsure + "REPLICA_SET_DFS" => 1, # unsure + "REPLICA_SET_OTHER" => 0, # unsure +); + +my %ads_gp_cse_extensions = ( +"Administrative Templates Extension" => "35378EAC-683F-11D2-A89A-00C04FBBCFA2", +"Disk Quotas" => "3610EDA5-77EF-11D2-8DC5-00C04FA31A66", +"EFS Recovery" => "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A", +"Folder Redirection" => "25537BA6-77A8-11D2-9B6C-0000F8080861", +"IP Security" => "E437BC1C-AA7D-11D2-A382-00C04F991E27", +"Internet Explorer Maintenance" => "A2E30F80-D7DE-11d2-BBDE-00C04F86AE3B", +"QoS Packet Scheduler" => "426031c0-0b47-4852-b0ca-ac3d37bfcb39", +"Scripts" => "42B5FAAE-6536-11D2-AE5A-0000F87571E3", +"Security" => "827D319E-6EAC-11D2-A4EA-00C04F79F83A", +"Software Installation" => "C6DC5466-785A-11D2-84D0-00C04FB169F7", +); + +# guess work +my %ads_gpcextensions = ( +"Administrative Templates" => "0F6B957D-509E-11D1-A7CC-0000F87571E3", +"Certificates" => "53D6AB1D-2488-11D1-A28C-00C04FB94F17", +"EFS recovery policy processing" => "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A", +"Folder Redirection policy processing" => "25537BA6-77A8-11D2-9B6C-0000F8080861", +"Folder Redirection" => "88E729D6-BDC1-11D1-BD2A-00C04FB9603F", +"Registry policy processing" => "35378EAC-683F-11D2-A89A-00C04FBBCFA2", +"Remote Installation Services" => "3060E8CE-7020-11D2-842D-00C04FA372D4", +"Security Settings" => "803E14A0-B4FB-11D0-A0D0-00A0C90F574B", +"Security policy processing" => "827D319E-6EAC-11D2-A4EA-00C04F79F83A", +"unknown" => "3060E8D0-7020-11D2-842D-00C04FA372D4", +"unknown2" => "53D6AB1B-2488-11D1-A28C-00C04FB94F17", +); + +my %ads_gpo_default_guids = ( +"Default Domain Policy" => "31B2F340-016D-11D2-945F-00C04FB984F9", +"Default Domain Controllers Policy" => "6AC1786C-016F-11D2-945F-00C04fB984F9", +"mist" => "61718096-3D3F-4398-8318-203A48976F9E", +); + +my %ads_uf = ( + "UF_SCRIPT" => 0x00000001, + "UF_ACCOUNTDISABLE" => 0x00000002, +# "UF_UNUSED_1" => 0x00000004, + "UF_HOMEDIR_REQUIRED" => 0x00000008, + "UF_LOCKOUT" => 0x00000010, + "UF_PASSWD_NOTREQD" => 0x00000020, + "UF_PASSWD_CANT_CHANGE" => 0x00000040, + "UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED" => 0x00000080, + "UF_TEMP_DUPLICATE_ACCOUNT" => 0x00000100, + "UF_NORMAL_ACCOUNT" => 0x00000200, +# "UF_UNUSED_2" => 0x00000400, + "UF_INTERDOMAIN_TRUST_ACCOUNT" => 0x00000800, + "UF_WORKSTATION_TRUST_ACCOUNT" => 0x00001000, + "UF_SERVER_TRUST_ACCOUNT" => 0x00002000, +# "UF_UNUSED_3" => 0x00004000, +# "UF_UNUSED_4" => 0x00008000, + "UF_DONT_EXPIRE_PASSWD" => 0x00010000, + "UF_MNS_LOGON_ACCOUNT" => 0x00020000, + "UF_SMARTCARD_REQUIRED" => 0x00040000, + "UF_TRUSTED_FOR_DELEGATION" => 0x00080000, + "UF_NOT_DELEGATED" => 0x00100000, + "UF_USE_DES_KEY_ONLY" => 0x00200000, + "UF_DONT_REQUIRE_PREAUTH" => 0x00400000, + "UF_PASSWORD_EXPIRED" => 0x00800000, + "UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION" => 0x01000000, + "UF_NO_AUTH_DATA_REQUIRED" => 0x02000000, +# "UF_UNUSED_8" => 0x04000000, +# "UF_UNUSED_9" => 0x08000000, +# "UF_UNUSED_10" => 0x10000000, +# "UF_UNUSED_11" => 0x20000000, +# "UF_UNUSED_12" => 0x40000000, +# "UF_UNUSED_13" => 0x80000000, +); + +my %ads_grouptype = ( + "GROUP_TYPE_BUILTIN_LOCAL_GROUP" => 0x00000001, + "GROUP_TYPE_ACCOUNT_GROUP" => 0x00000002, + "GROUP_TYPE_RESOURCE_GROUP" => 0x00000004, + "GROUP_TYPE_UNIVERSAL_GROUP" => 0x00000008, + "GROUP_TYPE_APP_BASIC_GROUP" => 0x00000010, + "GROUP_TYPE_APP_QUERY_GROUP" => 0x00000020, + "GROUP_TYPE_SECURITY_ENABLED" => 0x80000000, +); + +my %ads_atype = ( + "ATYPE_NORMAL_ACCOUNT" => 0x30000000, + "ATYPE_WORKSTATION_TRUST" => 0x30000001, + "ATYPE_INTERDOMAIN_TRUST" => 0x30000002, + "ATYPE_SECURITY_GLOBAL_GROUP" => 0x10000000, + "ATYPE_DISTRIBUTION_GLOBAL_GROUP" => 0x10000001, + "ATYPE_DISTRIBUTION_UNIVERSAL_GROUP" => 0x10000001, # ATYPE_DISTRIBUTION_GLOBAL_GROUP + "ATYPE_SECURITY_LOCAL_GROUP" => 0x20000000, + "ATYPE_DISTRIBUTION_LOCAL_GROUP" => 0x20000001, + "ATYPE_ACCOUNT" => 0x30000000, # ATYPE_NORMAL_ACCOUNT + "ATYPE_GLOBAL_GROUP" => 0x10000000, # ATYPE_SECURITY_GLOBAL_GROUP + "ATYPE_LOCAL_GROUP" => 0x20000000, # ATYPE_SECURITY_LOCAL_GROUP +); + +my %ads_gtype = ( + "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP" => 0x80000005, + "GTYPE_SECURITY_DOMAIN_LOCAL_GROUP" => 0x80000004, + "GTYPE_SECURITY_GLOBAL_GROUP" => 0x80000002, + "GTYPE_SECURITY_UNIVERSAL_GROUP" => 0x80000008, + "GTYPE_DISTRIBUTION_GLOBAL_GROUP" => 0x00000002, + "GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP" => 0x00000004, + "GTYPE_DISTRIBUTION_UNIVERSAL_GROUP" => 0x00000008, +); + +my %munged_dial = ( + "CtxCfgPresent" => \&dump_int, + "CtxCfgFlags1" => \&dump_int, + "CtxCallback" => \&dump_string, + "CtxShadow" => \&dump_string, + "CtxMaxConnectionTime" => \&dump_int, + "CtxMaxDisconnectionTime"=> \&dump_int, + "CtxMaxIdleTime" => \&dump_int, + "CtxKeyboardLayout" => \&dump_int, + "CtxMinEncryptionLevel" => \&dump_int, + "CtxWorkDirectory" => \&dump_string, + "CtxNWLogonServer" => \&dump_string, + "CtxWFHomeDir" => \&dump_string, + "CtxWFHomeDirDrive" => \&dump_string, + "CtxWFProfilePath" => \&dump_string, + "CtxInitialProgram" => \&dump_string, + "CtxCallbackNumber" => \&dump_string, +); + +$SIG{__WARN__} = sub { + use Carp; + Carp::cluck (shift); +}; + +# if there is data missing, we try to autodetect with samba-tools (if installed) +# this might fill up workgroup, machine, realm +get_samba_info(); + +# get a workgroup +$workgroup = $workgroup || $opt_workgroup || ""; + +# get the server +$server = process_servername($opt_host) || + detect_server($workgroup,$opt_realm) || + die "please define server to query with -h host\n"; + + +# get the base +$base = defined($opt_base)? $opt_base : "" || + get_base_from_rootdse($server,$dse); + +# get the realm +$realm = $opt_realm || + get_realm_from_rootdse($server,$dse); + +# get sasl mechs +my @sasl_mechs = get_sasl_mechs_from_rootdse($server,$dse); +my $sasl_mech = "GSSAPI"; +if ($opt_saslmech) { + $sasl_mech = sprintf("%s", (check_sasl_mech($opt_saslmech) == 0)?uc($opt_saslmech):""); +} + +# set bind type +my $sasl_bind = 1 if (!$opt_simpleauth); + +# get username +my $user = check_user($opt_user) || $ENV{'USER'} || ""; + +# gen upn +my $upn = sprintf("%s", gen_upn($opt_machine ? "$machine\$" : $user, $realm)); + +# get binddn +$binddn = $opt_binddn || $upn; + +# get the password +$password = $password || $opt_password; +if (!$password) { + $password = $opt_machine ? get_machine_password($workgroup) : get_password(); +} + +my %attr_handler = ( + "Token-Groups-No-GC-Acceptable" => \&dump_sid, #wrong name + "accountExpires" => \&dump_nttime, + "attributeSecurityGUID" => \&dump_guid, + "badPasswordTime" => \&dump_nttime, + "creationTime" => \&dump_nttime, + "currentTime" => \&dump_timestr, + "domainControllerFunctionality" => \&dump_ds_func, + "domainFunctionality" => \&dump_ds_func, + "fRSReplicaSetGUID" => \&dump_guid, + "fRSReplicaSetType" => \&dump_frstype, + "fRSVersionGUID" => \&dump_guid, + "flags" => \&dump_gpflags, # fixme: possibly only on gpos! + "forceLogoff" => \&dump_nttime_abs, + "forestFunctionality" => \&dump_ds_func, +# "gPCMachineExtensionNames" => \&dump_gpcextensions, +# "gPCUserExtensionNames" => \&dump_gpcextensions, + "gPLink" => \&dump_gplink, + "gPOptions" => \&dump_gpoptions, + "groupType" => \&dump_gtype, + "instanceType" => \&dump_instance_type, + "lastLogon" => \&dump_nttime, + "lastLogonTimestamp" => \&dump_nttime, + "lastSetTime" => \&dump_nttime, + "lockOutObservationWindow" => \&dump_nttime_abs, + "lockoutDuration" => \&dump_nttime_abs, + "lockoutTime" => \&dump_nttime, +# "logonHours" => \&dump_logonhours, + "maxPwdAge" => \&dump_nttime_abs, + "minPwdAge" => \&dump_nttime_abs, + "modifyTimeStamp" => \&dump_timestr, + "msDS-Behavior-Version" => \&dump_ds_func, #unsure + "msDS-User-Account-Control-Computed" => \&dump_uacc, + "msDS-SupportedEncryptionTypes" => \&dump_enctypes, + "mS-DS-CreatorSID" => \&dump_sid, +# "msRADIUSFramedIPAddress" => \&dump_ipaddr, +# "msRASSavedFramedIPAddress" => \&dump_ipaddr, + "netbootGUID" => \&dump_guid, + "nTMixedDomain" => \&dump_mixed_domain, + "nTSecurityDescriptor" => \&dump_secdesc, + "objectGUID" => \&dump_guid, + "objectSid" => \&dump_sid, + "pKT" => \&dump_pkt, + "pKTGuid" => \&dump_guid, + "priorSetTime" => \&dump_nttime, + "pwdLastSet" => \&dump_nttime, + "pwdProperties" => \&dump_pwdproperties, + "sAMAccountType" => \&dump_atype, + "schemaIDGUID" => \&dump_guid, + "sDRightsEffective" => \&dump_sdeffective, + "securityIdentifier" => \&dump_sid, + "serverState" => \&dump_serverstate, + "supportedCapabilities", => \&dump_capabilities, + "supportedControl", => \&dump_controls, + "supportedExtension", => \&dump_extension, + "systemFlags" => \&dump_systemflags, + "tokenGroups", => \&dump_sid, + "tokenGroupsGlobalAndUniversal" => \&dump_sid, + "tokenGroupsNoGCAcceptable" => \&dump_sid, + "trustAttributes" => \&dump_trustattr, + "trustDirection" => \&dump_trustdirection, + "trustType" => \&dump_trusttype, + "uASCompat" => \&dump_uascompat, + "userAccountControl" => \&dump_uac, + "userCertificate" => \&dump_cert, + "userFlags" => \&dump_uf, + "userParameters" => \&dump_munged_dial, + "whenChanged" => \&dump_timestr, + "whenCreated" => \&dump_timestr, +# "dSCorePropagationData" => \&dump_timestr, +); + + + +################ +# subfunctions # +################ + +sub usage { + print "usage: $0 [--asq] [--base|-b base] [--debug level] [--debug level] [--DN|-D binddn] [--extendeddn|-e] [--help] [--host|-h host] [--machine|-P] [--metadata|-m] [--nodiffs] [--notify|-n] [--password|-w password] [--port port] [--rawdisplay] [--realm|-R realm] [--rootdse] [--saslmech|-Y saslmech] [--schema|-c] [--scope|-s scope] [--simpleauth|-x] [--starttls|-Z] [--user|-U user] [--wknguid] [--workgroup|-k workgroup] filter [attrs]\n"; + print "\t--asq [attribute]\n\t\tAttribute to use for a attribute scoped query (LDAP_SERVER_ASQ_OID)\n"; + print "\t--base|-b [base]\n\t\tUse base [base]\n"; + print "\t--debug [level]\n\t\tUse debuglevel (for Net::LDAP)\n"; + print "\t--domain_scope\n\t\tLimit LDAP search to local domain (LDAP_SERVER_DOMAIN_SCOPE_OID)\n"; + print "\t--DN|-D [binddn]\n\t\tUse binddn or principal\n"; + print "\t--extendeddn|-e [value]\n\t\tDisplay extended dn (LDAP_SERVER_EXTENDED_DN_OID)\n"; + print "\t--fastbind\n\t\tDo LDAP fast bind using LDAP_SERVER_FAST_BIND_OID extension\n"; + print "\t--help\n\t\tDisplay help page\n"; + print "\t--host|-h [host]\n\t\tQuery Host [host] (either a hostname or an LDAP uri)\n"; + print "\t--machine|-P\n\t\tUse samba3 machine account stored in $secrets_tdb (needs root access)\n"; + print "\t--metdata|-m\n\t\tDisplay replication metadata\n"; + print "\t--nodiffs\n\t\tDisplay no diffs but full entry dump when running in notify mode\n"; + print "\t--notify|-n\n\t\tActivate asynchronous change notification (LDAP_SERVER_NOTIFICATION_OID)\n"; + print "\t--paging [pagesize]\n\t\tUse paged results when searching\n"; + print "\t--password|-w [password]\n\t\tUse [password] for binddn\n"; + print "\t--port [port]\n\t\tUse [port] when connecting ADS\n"; + print "\t--rawdisplay\n\t\tDo not interpret values\n"; + print "\t--realm|-R [realm]\n\t\tUse [realm] when trying to construct bind-principal\n"; + print "\t--rootdse\n\t\tDisplay RootDSE (anonymously)\n"; + print "\t--saslmech|-Y [saslmech]\n\t\tUse SASL Mechanism [saslmech] when binding\n"; + print "\t--schema|-c\n\t\tDisplay DSE-Schema\n"; + print "\t--scope|-s [scope]\n\t\tUse scope [scope] (sub, base, one)\n"; + print "\t--simpleauth|-x\n\t\tUse simple bind (otherwise SASL binds are performed)\n"; + print "\t--starttls|-Z\n\t\tUse Start TLS extended operation to secure LDAP traffic\n"; + print "\t--user|-U [user]\n\t\tUse [user]\n"; + print "\t--wknguid\n\t\tDisplay well known guids\n"; + print "\t--workgroup|-k [workgroup]\n\t\tWhen LDAP-Server is not known try to find a Domain-Controller for [workgroup]\n"; +} + +sub write_ads_list { + my ($mod,$attr,$value) = @_; + my $ofh = select(STDOUT); + $~ = "ADS_LIST"; + select($ofh); + write(); + +format ADS_LIST = +@<<<< @>>>>>>>>>>>>>>>>>>>>>>>: @* +$mod, $attr, $value +. +} + +sub write_ads { + my ($mod,$attr,$value) = @_; + my $ofh = select(STDOUT); + $~ = "ADS"; + select($ofh); + write(); + +format ADS = +@<<<< @>>>>>>>>>>>>>>>>>>>>>>>: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +$mod, $attr, $value +~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + $value +. +} + +sub detect_server { + + my $workgroup = shift; + my $realm = shift; + my $result; + my $found; + + # try net cache (nbt records) + if ( -x $net && $workgroup ) { + my $key = sprintf("NBT/%s#1C", uc($workgroup)); + chomp($result = `$net cache search $key 2>&1 /dev/null`); + $result =~ s/^.*Value: //; + $result =~ s/:.*//; + return $result if $result; + printf("%10s query failed for [%s]\n", "net cache", $key); + } + + # try dns SRV entries + if ( -x $dig && $realm ) { + my $key = sprintf("_ldap._tcp.%s", lc($realm)); + chomp($result = `$dig $key SRV +short +search | egrep "^[0-9]" | head -1`); + $result =~ s/.* //g; + $result =~ s/.$//g; + return $result if $result; + printf("%10s query failed for [%s]\n", "dns", $key); + } + + # try netbios broadcast query + if ( -x $nmblookup && $workgroup ) { + my $key = sprintf("%s#1C", uc($workgroup)); + my $pattern = sprintf("%s<1c>", uc($workgroup)); + chomp($result = `$nmblookup $key -d 0 | grep '$pattern'`); + $result =~ s/\s.*//; + return $result if $result; + printf("%10s query failed for [%s]\n", "nmblookup", $key); + } + + return ""; +} + +sub get_samba_info { + + if (! -x $testparm) { return -1; } + + my $tmp; + open(TESTPARM, "$testparm -s -v 2> /dev/null |"); + while (my $line = <TESTPARM>) { + chomp($line); + if ($line =~ /netbios name/) { + ($tmp, $machine) = split(/=/, $line); + $machine =~ s/\s+|\t+//g; + } + if ($line =~ /realm/) { + ($tmp, $realm) = split(/=/, $line); + $realm =~ s/\s+|\t+//g; + } + if ($line =~ /workgroup/) { + ($tmp, $workgroup) = split(/=/, $line); + $workgroup =~ s/\s+|\t+//g; + } + } + close(TESTPARM); + return 0; +} + +sub gen_upn { + my $machine = shift; + my $realm = shift; + if ($machine && $realm) { + return sprintf("%s\@%s", lc($machine), uc($realm)); + }; + return undef; +} + +sub get_password { + if (!$password && $opt_simpleauth && check_ticket($user)) { + return prompt_password($user); + } + return ""; +} + +sub get_user { + my $user = shift || prompt_user(); + return $user; +} + +sub get_machine_password { + + my $workgroup = shift || ""; + $workgroup = uc($workgroup); + + my ($found, $tmp, $dbdump, $db); + if (-r $secrets_ntdb) { + -x $ntdbdump || die "ntdbdump is not installed. cannot proceed autodetection\n"; + $dbdump = $ntdbdump; + $db = $secrets_ntdb; + } else { + -x $tdbdump || die "tdbdump is not installed. cannot proceed autodetection\n"; + -r $secrets_tdb || die "cannot read $secrets_tdb. cannot proceed autodetection\n"; + $dbdump = $tdbdump; + $db = $secrets_tdb; + } + + # get machine-password + my $key = sprintf("SECRETS/MACHINE_PASSWORD/%s", $workgroup); + open(SECRETS,"$dbdump $db |"); + while(my $line = <SECRETS>) { + chomp($line); + if ($found) { + $line =~ s/\\00//; + ($line,$password) = split(/"/, $line); + last; + } + if ($line =~ /\"$key\"/) { + $found = 1; + } + } + close(SECRETS); + + if ($found) { + print "Successfully autodetected machine password for workgroup: $workgroup\n"; + return $password; + } else { + warn "No machine password available for $workgroup\n"; + } + return ""; +} + +sub prompt_password { + + my $acct = shift || ""; + if ($acct =~ /\%/) { + ($acct, $password) = split(/\%/, $acct); + return $password; + } + system "stty -echo"; + print "Enter password for $acct:"; + my $password = <STDIN>; + chomp($password); + print "\n"; + system "stty echo"; + return $password; +} + +sub prompt_user { + + print "Enter Username:"; + my $user = <STDIN>; + chomp($user); + print "\n"; + return $user; +} + +sub check_ticket { + return 0; + # works only for heimdal + return system("$klist -t"); +} + +sub get_ticket { + + my $KRB5_CONFIG = "/tmp/.krb5.conf.telads-$<"; + + open(KRB5CONF, "> $KRB5_CONFIG") || die "cannot write $KRB5_CONFIG"; + printf KRB5CONF "# autogenerated by $0\n"; + printf KRB5CONF "[libdefaults]\n\tdefault_realm = %s\n\tclockskew = %d\n", uc($realm), 60*60; + printf KRB5CONF "[realms]\n\t%s = {\n\t\tkdc = %s\n\t}\n", uc($realm), $server; + close(KRB5CONF); + + if ( system("KRB5_CONFIG=$KRB5_CONFIG $kinit $user") != 0) { + return -1; + } + + return 0; +} + +sub check_user { + my $acct = shift || ""; + if ($acct =~ /\%/) { + ($acct, $password) = split(/\%/, $acct); + } + return $acct; +} + +sub check_root_dse($$$@) { + + # bogus function?? + my $server = shift || ""; + $dse = shift || get_dse($server) || return -1; + my $attr = shift || die "unknown query"; + my @array = @_; + + my $dse_list = $dse->get_value($attr, asref => '1'); + my @dse_array = @$dse_list; + + foreach my $i (@array) { + # we could use -> supported_control but this + # is only available in newer versions of perl-ldap +# if ( ! $dse->supported_control( $i ) ) { + if ( grep(/$i->type()/, @dse_array) ) { + printf("required \"$attr\": %s is not supported by ADS-server.\n", $i->type()); + return -1; + } + } + return 0; +} + +sub check_ctrls ($$@) { + my $server = shift; + my $dse = shift; + my @array = @_; + return check_root_dse($server, $dse, "supportedControl", @array); +} + +sub check_exts ($$@) { + my $server = shift; + my $dse = shift; + my @array = @_; + return check_root_dse($server, $dse, "supportedExtension", @array); +} + +sub get_base_from_rootdse { + + my $server = shift || ""; + $dse = shift || get_dse($server,$async_ldap_hd) || return -1; + return $dse->get_value($opt_dump_schema ? 'schemaNamingContext': + 'defaultNamingContext'); +} + +sub get_realm_from_rootdse { + + my $server = shift || ""; + $dse = shift || get_dse($server,$async_ldap_hd) || return -1; + my $service = $dse->get_value('ldapServiceName') || ""; + if ($service) { + my ($t,$realm) = split(/\@/, $service); + return $realm; + } else { + die "very odd: could not get realm"; + } +} + +sub get_sasl_mechs_from_rootdse { + + my $server = shift || ""; + $dse = shift || get_dse($server,$async_ldap_hd) || return -1; + my $mechs = $dse->get_value('supportedSASLMechanisms', asref => 1); + return @$mechs; +} + +sub get_dse { + + my $server = shift || return undef; + $async_ldap_hd = shift || get_ldap_hd($server,1); + if (!$async_ldap_hd) { + print "oh, no connection\n"; + return undef; + } + my $mesg = $async_ldap_hd->bind() || die "cannot bind\n"; + if ($mesg->code) { die "failed to bind\n"; }; + my $dse = $async_ldap_hd->root_dse( attrs => ['*', "supportedExtension", "supportedFeatures" ] ); + + return $dse; +} + +sub process_servername { + + my $name = shift || return ""; + if ($name =~ /^ldaps:\/\//i ) { + $name =~ s#^ldaps://##i; + $uri = sprintf("%s://%s", "ldaps", $name); + } else { + $name =~ s#^ldap://##i; + $uri = sprintf("%s://%s", "ldap", $name); + } + return $name; +} + +sub get_ldap_hd { + + my $server = shift || return undef; + my $async = shift || "0"; + my $hd; + die "uri unavailable" if (!$uri); + if ($uri =~ /^ldaps:\/\//i ) { + $port = $port || 636; + use Net::LDAPS; + $hd = Net::LDAPS->new( $server, async => $async, port => $port ) || + die "host $server not available: $!"; + } else { + $port = $port || 389; + $hd = Net::LDAP->new( $server, async => $async, port => $port ) || + die "host $server not available: $!"; + } + $hd->debug($opt_debug); + if ($opt_starttls) { + $hd->start_tls( verify => 'none' ); + } + + return $hd; +} + +sub get_sasl_hd { + + if (!$have_sasl) { + print "no sasl support\n"; + return undef; + } + + my $hd; + if ($sasl_mech && $sasl_mech eq "GSSAPI") { + my $user = sprintf("%s\@%s", $user, uc($realm)); + if (check_ticket($user) != 0 && get_ticket($user) != 0) { + print "Could not get Kerberos ticket for user [$user]\n"; + return undef; + } + + $hd = Authen::SASL->new( mechanism => 'GSSAPI' ) || die "nope"; + my $conn = $hd->client_new("ldap", $server); + + if ($conn->code == -1) { + printf "%s\n", $conn->error(); + return undef; + }; + + } elsif ($sasl_mech) { + + # here comes generic sasl code + $hd = Authen::SASL->new( mechanism => $sasl_mech, + callback => { + user => \&get_user, + pass => \&get_password + } + ) || die "nope"; + } else { + $sasl_bind = 0; + print "no supported SASL mechanism found (@sasl_mechs).\n"; + print "falling back to simple bind.\n"; + return undef; + } + + return $hd; +} + +sub check_sasl_mech { + my $mech_check = shift; + my $have_mech = 0; + foreach my $mech (@sasl_mechs) { + $have_mech = 1 if ($mech eq uc($mech_check)); + } + if (!$have_mech) { + return -1; + } + return 0; +} + +sub store_result ($) { + + my $entry = shift; + return if (!$entry); + $entry_store{$entry->dn} = $entry; +} + +sub display_result_diff ($) { + + my $entry_new = shift; + return if ( !$entry_new); + + if ( !exists $entry_store{$entry_new->dn}) { + print "can't display any differences yet. full dump...\n"; + display_entry_generic($entry_new); + return; + } + + my $entry_old = $entry_store{$entry_new->dn}; + + foreach my $attr (sort $entry_new->attributes) { + if ( $entry_new->exists($attr) && ! $entry_old->exists($attr)) { + display_attr_generic("add:\t", $entry_new, $attr); + next; + } + } + + foreach my $attr (sort $entry_old->attributes) { + if (! $entry_new->exists($attr) && $entry_old->exists($attr)) { + display_attr_generic("del:\t", $entry_old, $attr); + next; + } + + # now check for all values if they have changed, display changes + my ($old_vals, $new_vals, @old_vals, @new_vals, %old, %new); + + $old_vals = $entry_old->get_value($attr, asref => 1); + @old_vals = @$old_vals; + $new_vals = $entry_new->get_value($attr, asref => 1); + @new_vals = @$new_vals; + + if (scalar(@old_vals) == 1 && scalar(@new_vals) == 1) { + if ($old_vals[0] ne $new_vals[0]) { + display_attr_generic("old:\t", $entry_old, $attr); + display_attr_generic("new:\t", $entry_new, $attr); + } + next; + } + + # handle multivalued diffs + foreach my $val (@old_vals) { $old{$val} = "dummy"; }; + foreach my $val (@new_vals) { $new{$val} = "dummy"; }; + foreach my $val (sort keys %new) { + if (!exists $old{$val}) { + display_value_generic("add:\t", $attr, $val); + } + } + foreach my $val (sort keys %old) { + if (!exists $new{$val}) { + display_value_generic("del:\t", $attr, $val); + } + } + } + print "\n"; + +} + +sub sid2string ($) { + + # Fix from Michael James <michael@james.st> + my $binary_sid = shift; + my($sid_rev, $num_auths, $id1, $id2, @ids) = unpack("H2 H2 n N V*", $binary_sid); + my $sid_string = join("-", "S", hex($sid_rev), ($id1<<32)+$id2, @ids); + return $sid_string; + +} + +sub string_to_guid { + my $string = shift; + return undef unless $string =~ /([0-9,a-z]{8})-([0-9,a-z]{4})-([0-9,a-z]{4})-([0-9,a-z]{2})([0-9,a-z]{2})-([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})/i; + + return pack("I", hex $1) . + pack("S", hex $2) . + pack("S", hex $3) . + pack("C", hex $4) . + pack("C", hex $5) . + pack("C", hex $6) . + pack("C", hex $7) . + pack("C", hex $8) . + pack("C", hex $9) . + pack("C", hex $10) . + pack("C", hex $11); + +# print "$1\n$2\n$3\n$4\n$5\n$6\n$7\n$8\n$9\n$10\n$11\n"; +} + +sub bindstring_to_guid { + my $str = shift; + return pack("H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2", + substr($str,0,2), + substr($str,2,2), + substr($str,4,2), + substr($str,6,2), + substr($str,8,2), + substr($str,10,2), + substr($str,12,2), + substr($str,14,2), + substr($str,16,2), + substr($str,18,2), + substr($str,20,2), + substr($str,22,2), + substr($str,24,2), + substr($str,26,2), + substr($str,28,2), + substr($str,30,2)); +} + +sub guid_to_string { + my $guid = shift; + my $string = sprintf "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + unpack("I", $guid), + unpack("S", substr($guid, 4, 2)), + unpack("S", substr($guid, 6, 2)), + unpack("C", substr($guid, 8, 1)), + unpack("C", substr($guid, 9, 1)), + unpack("C", substr($guid, 10, 1)), + unpack("C", substr($guid, 11, 1)), + unpack("C", substr($guid, 12, 1)), + unpack("C", substr($guid, 13, 1)), + unpack("C", substr($guid, 14, 1)), + unpack("C", substr($guid, 15, 1)); + return lc($string); +} + +sub guid_to_bindstring { + my $guid = shift; + return unpack("H" . 2 * length($guid), $guid), +} + +sub dump_wknguid { + print "Dumping Well known GUIDs:\n"; + foreach my $wknguid (keys %wknguids) { + + my $guid = bindstring_to_guid($wknguids{$wknguid}); + my $str = guid_to_string($guid); + my $back = guid_to_bindstring($guid); + + printf "wkguid: %s\n", $wknguid; + printf "bind_string format: %s\n", $wknguids{$wknguid}; + printf "string format: %s\n", guid_to_string($guid); + printf "back to bind_string:%s\n", guid_to_bindstring($guid); + + printf "use base: \"<WKGUID=%s,%s>\"\n", guid_to_bindstring($guid), $base; + } +} + +sub gen_bitmask_string_format($%) { + my $mod = shift; + my (%tmp) = @_; + my @list; + foreach my $key (sort keys %tmp) { + push(@list, sprintf("%s %s", $tmp{$key}, $key)); + } + return join("\n$mod$tabsize",@list); +} + + +sub nt_to_unixtime ($) { + # the number of 100 nanosecond intervals since jan. 1. 1601 (utc) + my $t64 = shift; + $t64 =~ s/(.+).{7,7}/$1/; + $t64 -= 11644473600; + return $t64; +} + +sub dump_equal { + my $val = shift; + my $mod = shift || die "no mod"; + my (%header) = @_; + my %tmp; + my $found = 0; + foreach my $key (keys %header) { + if ($header{$key} eq $val) { + $tmp{"($val)"} = $key; + $found = 1; + last; + } + } + if (!$found) { $tmp{$val} = ""; }; + return gen_bitmask_string_format($mod,%tmp); +} + +sub dump_bitmask { + my $op = shift || die "no op"; + my $val = shift; + my $mod = shift || die "no mod"; + my (%header) = @_; + my %tmp; + $tmp{""} = sprintf("%s (0x%08x)", $val, $val); + foreach my $key (sort keys %header) { # sort by val ! + my $val_hex = sprintf("0x%08x", $header{$key}); + if ($op eq "&") { + $tmp{"$key ($val_hex)"} = ( $val & $header{$key} ) ? $set:$unset; + } elsif ($op eq "==") { + $tmp{"$key ($val_hex)"} = ( $val == $header{$key} ) ? $set:$unset; + } else { + print "unknown operator: $op\n"; + return; + } + } + return gen_bitmask_string_format($mod,%tmp); +} + +sub dump_bitmask_and { + return dump_bitmask("&",@_); +} + +sub dump_bitmask_equal { + return dump_bitmask("==",@_); +} + +sub dump_uac { + return dump_bitmask_and(@_,%ads_uf); # ads_uf ? +} + +sub dump_uascompat { + return dump_bitmask_equal(@_,%ads_uascompat); +} + +sub dump_gpoptions { + return dump_bitmask_equal(@_,%ads_gpoptions); +} + +sub dump_gpflags { + return dump_bitmask_equal(@_,%ads_gpflags); +} + +sub dump_uacc { + return dump_bitmask_equal(@_,%ads_uacc); +} + +sub dump_enctypes { + return dump_bitmask_and(@_,%ads_enctypes); +} + +sub dump_uf { + return dump_bitmask_and(@_,%ads_uf); +} + +sub dump_gtype { + my $ret = dump_bitmask_and(@_,%ads_grouptype); + $ret .= "\n$tabsize\t"; + $ret .= dump_bitmask_equal(@_,%ads_gtype); + return $ret; +} + +sub dump_atype { + return dump_bitmask_equal(@_,%ads_atype); +} + +sub dump_controls { + return dump_equal(@_,%ads_controls); +} + +sub dump_capabilities { + return dump_equal(@_,%ads_capabilities); +} + +sub dump_extension { + return dump_equal(@_,%ads_extensions); +} + +sub dump_systemflags { + return dump_bitmask_and(@_,%ads_systemflags); +} + +sub dump_instance_type { + return dump_bitmask_and(@_,%ads_instance_type); +} + +sub dump_ds_func { + return dump_bitmask_equal(@_,%ads_ds_func); +} + +sub dump_serverstate { + return dump_bitmask_equal(@_,%ads_serverstate); +} + +sub dump_sdeffective { + return dump_bitmask_and(@_,%ads_sdeffective); +} + +sub dump_trustattr { + return dump_bitmask_and(@_,%ads_trustattrs); +} + +sub dump_trusttype { + return dump_bitmask_equal(@_,%ads_trusttype); +} + +sub dump_trustdirection { + return dump_bitmask_equal(@_,%ads_trustdirection); +} + +sub dump_pwdproperties { + return dump_bitmask_and(@_,%ads_pwdproperties); +} + +sub dump_frstype { + return dump_bitmask_equal(@_,%ads_frstypes) +} + +sub dump_mixed_domain { + return dump_bitmask_equal(@_,%ads_mixed_domain); +} + +sub dump_sid { + my $bin_sid = shift; + return sid2string($bin_sid); +} + +sub dump_guid { + my $guid = shift; + return guid_to_string($guid); +} + +sub dump_secdesc { + my $val = shift; + return "FIXME: write sddl-converter!"; +} + +sub dump_nttime { + my $nttime = shift; + if ($nttime == 0) { + return sprintf("%s (%s)", "never", $nttime); + } + my $localtime = localtime(nt_to_unixtime($nttime)); + return sprintf("%s (%s)", $localtime, $nttime); +} + +sub dump_nttime_abs { + if ($_[0] == 9223372036854775807) { + return sprintf("%s (%s)", "now", $_[0]); + } + if ($_[0] == -9223372036854775808 || $_[0] == 0) { # 0x7FFFFFFFFFFFFFFF + return sprintf("%s (%s)", "never", $_[0]); + } + # FIXME: actually *do* abs time ! + return dump_nttime($_[0]); +} + +sub dump_timestr { + my $time = shift; + if ($time eq "16010101000010.0Z") { + return sprintf("%s (%s)", "never", $time); + } + my ($year,$mon,$mday,$hour,$min,$sec,$zone) = + unpack('a4 a2 a2 a2 a2 a2 a4', $time); + $mon -= 1; + my $localtime = localtime(timegm($sec,$min,$hour,$mday,$mon,$year)); + return sprintf("%s (%s)", $localtime, $time); +} + +sub dump_string { + return $_[0]; +} + +sub dump_int { + return sprintf("%d", $_[0]); +} + +sub dump_munged_dial { + my $dial = shift; + return "FIXME! decode this"; +} + +sub dump_cert { + + my $cert = shift; + open(OPENSSL, "| /usr/bin/openssl x509 -text -inform der"); + print OPENSSL $cert; + close(OPENSSL); + return ""; +} + +sub dump_pkt { + my $pkt = shift; + return "not yet"; + printf("%s: ", $pkt); + printf("%02X", $pkt); + +} + +sub dump_gplink { + + my $gplink = shift; + my $gplink_mod = $gplink; + my @links = split("\\]\\[", $gplink_mod); + foreach my $link (@links) { + $link =~ s/^\[|\]$//g; + my ($ldap_link, $opt) = split(";", $link); + my @array = ( "$opt", "\t" ); + printf("%slink: %s, opt: %s\n", $tabsize, $ldap_link, dump_bitmask_and(@array, %ads_gplink_opts)); + } + return $gplink; +} + +sub construct_filter { + + my $tmp = shift; + + if (!$tmp || $opt_notify) { + return "(objectclass=*)"; + } + + if ($tmp && $tmp !~ /^.*\=/) { + return "(ANR=$tmp)"; + } + + return $tmp; + # (&(objectCategory=person) + # (userAccountControl:$ads_matching_rules{LDAP_MATCHING_RULE_BIT_AND}:=2)) +} + +sub construct_attrs { + + my @attrs = @_; + + if (!@attrs) { + push(@attrs,"*"); + } + + if ($opt_notify) { + push(@attrs,"uSNChanged"); + } + + if ($opt_display_metadata) { + push(@attrs,"msDS-ReplAttributeMetaData"); + push(@attrs,"replPropertyMetaData"); + } + + if ($opt_verbose) { + push(@attrs,"nTSecurityDescriptor"); + push(@attrs,"msDS-KeyVersionNumber"); + push(@attrs,"msDS-User-Account-Control-Computed"); + push(@attrs,"modifyTimeStamp"); + } + + return sort @attrs; +} + +sub print_header { + + print "\n"; + printf "%10s: %s\n", "uri", $uri; + printf "%10s: %s\n", "port", $port; + printf "%10s: %s\n", "base", $base; + printf "%10s: %s\n", $sasl_bind ? "principal" : "binddn", $sasl_bind ? $upn : $binddn; + printf "%10s: %s\n", "password", $password; + printf "%10s: %s\n", "bind-type", $sasl_bind ? "SASL" : "simple"; + printf "%10s: %s\n", "sasl-mech", $sasl_mech if ($sasl_mech); + printf "%10s: %s\n", "filter", $filter; + printf "%10s: %s\n", "scope", $scope; + printf "%10s: %s\n", "attrs", join(", ", @attrs); + printf "%10s: %s\n", "controls", join(", ", @ctrls_s); + printf "%10s: %s\n", "page_size", $opt_paging if ($opt_paging); + printf "%10s: %s\n", "start_tls", $opt_starttls ? "yes" : "no"; + printf "\n"; +} + +sub gen_controls { + + # setup attribute-scoped query control + my $asq_asn = Convert::ASN1->new; + $asq_asn->prepare( + q< asq ::= SEQUENCE { + sourceAttribute OCTET_STRING + } + > + ); + my $ctl_asq_val = $asq_asn->encode( sourceAttribute => $opt_asq); + my $ctl_asq = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_ASQ_OID'}, + critical => 'true', + value => $ctl_asq_val); + + + # setup extended dn control + my $asn_extended_dn = Convert::ASN1->new; + $asn_extended_dn->prepare( + q< ExtendedDn ::= SEQUENCE { + mode INTEGER + } + > + ); + + # only w2k3 accepts '1' and needs the ctl_val, w2k does not accept a ctl_val + my $ctl_extended_dn_val = $asn_extended_dn->encode( mode => $opt_display_extendeddn); + my $ctl_extended_dn = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_EXTENDED_DN_OID'}, + critical => 'true', + value => $opt_display_extendeddn ? $ctl_extended_dn_val : ""); + + # setup search options + my $search_opt = Convert::ASN1->new; + $search_opt->prepare( + q< searchopt ::= SEQUENCE { + flags INTEGER + } + > + ); + + my $tmp = $search_opt->encode( flags => $opt_search_opt); + my $ctl_search_opt = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_SEARCH_OPTIONS_OID'}, + critical => 'true', + value => $tmp); + + # setup notify control + my $ctl_notification = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_NOTIFICATION_OID'}, + critical => 'true'); + + + # setup paging control + $ctl_paged = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_PAGED_RESULT_OID_STRING'}, + critical => 'true', + size => $opt_paging ? $opt_paging : 1000); + + # setup domscope control + my $ctl_domscope = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_DOMAIN_SCOPE_OID'}, + critical => 'true', + value => ""); + + if (defined($opt_paging) || $opt_dump_schema) { + push(@ctrls, $ctl_paged); + push(@ctrls_s, "LDAP_PAGED_RESULT_OID_STRING" ); + } + + if (defined($opt_display_extendeddn)) { + push(@ctrls, $ctl_extended_dn); + push(@ctrls_s, "LDAP_SERVER_EXTENDED_DN_OID"); + } + if ($opt_notify) { + push(@ctrls, $ctl_notification); + push(@ctrls_s, "LDAP_SERVER_NOTIFICATION_OID"); + } + + if ($opt_asq) { + push(@ctrls, $ctl_asq); + push(@ctrls_s, "LDAP_SERVER_ASQ_OID"); + } + + if ($opt_domain_scope) { + push(@ctrls, $ctl_domscope); + push(@ctrls_s, "LDAP_SERVER_DOMAIN_SCOPE_OID"); + } + + if ($opt_search_opt) { + push(@ctrls, $ctl_search_opt); + push(@ctrls_s, "LDAP_SERVER_SEARCH_OPTIONS_OID"); + } + + return @ctrls; +} + +sub display_value_generic ($$$) { + + my ($mod,$attr,$value) = @_; + return unless (defined($value) and defined($attr)); + + if ( ! $opt_display_raw && exists $attr_handler{$attr} ) { + $value = $attr_handler{$attr}($value,$mod); + write_ads_list($mod,$attr,$value); + return; + } + write_ads($mod,$attr,$value); +} + +sub display_attr_generic ($$$) { + + my ($mod,$entry,$attr) = @_; + return if (!$attr || !$entry); + + my $ref = $entry->get_value($attr, asref => 1); + my @values = @$ref; + + foreach my $value ( sort @values) { + display_value_generic($mod,$attr,$value); + } +} + +sub display_entry_generic ($) { + + my $entry = shift; + return if (!$entry); + + foreach my $attr ( sort $entry->attributes) { + display_attr_generic("\t",$entry,$attr); + } +} + +sub display_ldap_err ($) { + + my $msg = shift; + print_header(); + my ($package, $filename, $line, $subroutine) = caller(0); + + print "got error from ADS:\n"; + printf("%s(%d): ERROR (%s): %s\n", + $subroutine, $line, $msg->code, $msg->error); + +} + +sub process_result { + + my ($msg,$entry) = @_; + + if (!defined($msg)) { + return; + } + + if ($msg->code) { + display_ldap_err($msg); + exit 1; + } + + if (!defined($entry)) { + return; + } + + if ($entry->isa('Net::LDAP::Reference')) { + foreach my $ref ($entry->references) { + print "\ngot Reference: [$ref]\n"; + } + return; + } + + print "\nfound entry: ".$entry->dn."\n".("-" x 80)."\n"; + + display_entry_generic($entry); +} + +sub default_callback { + + my ($res,$obj) = @_; + + if (!$opt_notify && $res->code == LDAP_REFERRAL) { + return; + } + + if (!$opt_notify) { + return process_result($res,$obj); + } +} + +sub error_callback { + + my ($msg,$entry) = @_; + + if (!$msg) { + return; + } + + if ($msg->code) { + display_ldap_err($msg); + exit(1); + } + return; +} + +sub notify_callback { + + my ($msg, $obj) = @_; + + if (! defined($obj)) { + return; + } + + if ($obj->isa('Net::LDAP::Reference')) { + foreach my $ref ($obj->references) { + print "\ngot Reference: [$ref]\n"; + } + return; + } + + while (1) { + + my $async_entry = $async_search->pop_entry; + + if (!$async_entry->dn) { + print "very weird. entry has no dn\n"; + next; + } + + printf("\ngot changenotify for dn: [%s]\n%s\n", $async_entry->dn, ("-" x 80)); + + my $new_usn = $async_entry->get_value('uSNChanged'); + if (!$new_usn) { + die "odd, no usnChanged attribute???"; + } + if (!$usn || $new_usn > $usn) { + $usn = $new_usn; + if ($opt_notify_nodiffs) { + display_entry_generic($async_entry); + } else { + display_result_diff($async_entry); + } + } + store_result($async_entry); + } +} + +sub do_bind($$) { + + my $async_ldap_hd = shift || return undef; + my $sasl_bind = shift; + + if ($sasl_bind) { + if (!$works_sasl) { + print "this version of Net::LDAP does not have proper SASL support.\n"; + print "Need at least perl-ldap V. $pref_version\n"; + } + $sasl_hd = get_sasl_hd(); + if (!$sasl_hd) { + print "failed to create SASL handle\n"; + return -1; + } + $mesg = $async_ldap_hd->bind( + sasl => $sasl_hd, + callback => \&error_callback + ) || die "doesn't work"; + } else { + $sasl_mech = ""; + $mesg = $async_ldap_hd->bind( + $binddn, + password => $password, + callback => $opt_fastbind ? undef : \&error_callback + ) || die "doesn't work"; + }; + if ($mesg->code) { + display_ldap_err($mesg) if (!$opt_fastbind); + return -1; + } + return 0; +} + +sub do_fast_bind() { + + do_unbind(); + + my $hd = get_ldap_hd($server,1); + + my $mesg = $hd->extension( + name => $ads_extensions{'LDAP_SERVER_FAST_BIND_OID'}); + + if ($mesg->code) { + display_ldap_err($mesg); + return -1; + } + + my $ret = do_bind($hd, undef); + $hd->unbind; + + printf("bind using 'LDAP_SERVER_FAST_BIND_OID' %s\n", + $ret == 0 ? "succeeded" : "failed"); + + return $ret; +} + +sub do_unbind() { + if ($async_ldap_hd) { + $async_ldap_hd->unbind; + } + if ($sync_ldap_hd) { + $sync_ldap_hd->unbind; + } +} + +############################################################################### + +sub main () { + + if ($opt_fastbind) { + + if (check_exts($server,$dse,"LDAP_SERVER_FAST_BIND_OID") == -1) { + print "LDAP_SERVER_FAST_BIND_OID not supported by this server\n"; + exit 1; + } + + # fast bind can only bind, not search + exit do_fast_bind(); + } + + $filter = construct_filter($query); + @attrs = construct_attrs(@attrs); + @ctrls = gen_controls(); + + if (check_ctrls($server,$dse,@ctrls) == -1) { + print "not all required LDAP Controls are supported by this server\n"; + exit 1; + } + + if ($opt_dump_rootdse) { + print "Dumping Root-DSE:\n"; + display_entry_generic($dse); + exit 0; + } + + if ($opt_dump_wknguid) { + dump_wknguid(); + exit 0; + } + + if (do_bind($async_ldap_hd, $sasl_bind) == -1) { + exit 1; + } + + print_header(); + + if ($opt_dump_schema) { + print "Dumping Schema:\n"; +# my $ads_schema = $async_ldap_hd->schema; +# $ads_schema->dump; +# exit 0; + } + + while (1) { + + $async_search = $async_ldap_hd->search( + base => $base, + filter => $filter, + attrs => [ @attrs ], + control => [ @ctrls ], + callback => \&default_callback, + scope => $scope, + ) || die "cannot search"; + + if (!$opt_notify && ($async_search->code == LDAP_REFERRAL)) { + foreach my $ref ($async_search->referrals) { + print "\ngot Referral: [$ref]\n"; + my ($prot, $host, $base) = split(/\/+/, $ref); + $async_ldap_hd->unbind(); + $async_ldap_hd = get_ldap_hd($host, 1); + if (do_bind($async_ldap_hd, $sasl_bind) == -1) { + $async_ldap_hd->unbind(); + next; + } + print "\nsuccessful rebind to: [$ref]\n"; + last; + } + next; # repeat the query + } + + if ($opt_notify) { + + print "Base [$base] is registered now for change-notify\n"; + print "\nWaiting for change-notify...\n"; + + my $sync_ldap_hd = get_ldap_hd($server,0); + if (do_bind($sync_ldap_hd, $sasl_bind) == -1) { + exit 2; + } + + my $sync_search = $sync_ldap_hd->search( + base => $base, + filter => $filter, + attrs => [ @attrs ], + callback => \¬ify_callback, + scope => $scope, + ) || die "cannot search"; + + } + + $total_entry_count += $async_search->count; + ++$page_count; + print "-" x 80 . "\n"; + printf("Got %d Entries in Page %d \n\n", + $async_search->count, $page_count); + my ($resp) = $async_search->control( + $ads_controls{'LDAP_PAGED_RESULT_OID_STRING'} ) or last; + last unless ref $resp && $ctl_paged->cookie($resp->cookie); + } + + if ($async_search->entries == 0) { + print "No entries found with filter $filter\n"; + } else { + print "Got $total_entry_count Entries in $page_count Pages\n" if ($opt_paging); + } + + do_unbind() +} + +main(); + +exit 0; diff --git a/examples/misc/check_multiple_LDAP_entries.pl b/examples/misc/check_multiple_LDAP_entries.pl new file mode 100755 index 0000000..00c197a --- /dev/null +++ b/examples/misc/check_multiple_LDAP_entries.pl @@ -0,0 +1,201 @@ +#!/usr/bin/perl -w +# Guenther Deschner <gd@samba.org> +# +# check for multiple LDAP entries + +use strict; + +use Net::LDAP; +use Getopt::Std; + +my %opts; + +if (!@ARGV) { + print "usage: $0 -h host -b base -D admindn -w password [-l]\n"; + print "\tperforms checks for multiple sid, uid and gid-entries on your LDAP server\n"; + print "\t-l adds additional checks against the local /etc/passwd and /etc/group file\n"; + exit 1; +} + +getopts('b:h:D:w:l', \%opts); + +my $host = $opts{h} || "localhost"; +my $suffix = $opts{b} || die "please set base with -b"; +my $binddn = $opts{D} || die "please set basedn with -D"; +my $bindpw = $opts{w} || die "please set password with -w"; +my $check_local_files = $opts{l} || 0; + +######################## + + +my ($ldap, $res); +my (%passwd_h, %group_h); +my $bad_uids = 0; +my $bad_gids = 0; +my $bad_sids = 0; +my $ret = 0; + +if ($check_local_files) { + my @uids = `cut -d ':' -f 3 /etc/passwd`; + my @gids = `cut -d ':' -f 3 /etc/group`; + + foreach my $uid (@uids) { + chomp($uid); + $passwd_h{$uid} = $uid; + } + + foreach my $gid (@gids) { + chomp($gid); + $group_h{$gid} = $gid; + } +} + +######## +# bind # +######## + +$ldap = Net::LDAP->new($host, version => '3'); + +$res = $ldap->bind( $binddn, password => $bindpw); +$res->code && die "failed to bind: ", $res->error; + + + +########################### +# check for double sids # +########################### + +print "\ntesting for multiple sambaSids\n"; + +$res = $ldap->search( + base => $suffix, + filter => "(objectclass=sambaSamAccount)"); + +$res->code && die "failed to search: ", $res->error; + +foreach my $entry ($res->all_entries) { + + my $sid = $entry->get_value('sambaSid'); + + my $local_res = $ldap->search( + base => $suffix, + filter => "(&(objectclass=sambaSamAccount)(sambaSid=$sid))"); + + $local_res->code && die "failed to search: ", $local_res->error; + if ($local_res->count > 1) { + print "A SambaSamAccount with sambaSid [$sid] must exactly exist once\n"; + print "You have ", $local_res->count, " entries:\n"; + foreach my $loc_entry ($local_res->all_entries) { + printf "\t%s\n", $loc_entry->dn; + } + ++$bad_sids; + } +} + +if ($bad_sids) { + $ret = -1; + print "You have $bad_sids bad sambaSids in your system. You might need to repair them\n"; +} else { + print "No multiple sambaSids found in your system\n"; +} + +print "-" x 80, "\n"; + +########################### +# check for double groups # +########################### + +print "\ntesting for multiple gidNumbers\n"; + +$res = $ldap->search( + base => $suffix, + filter => "(objectclass=posixGroup)"); + +$res->code && die "failed to search: ", $res->error; + +foreach my $entry ($res->all_entries) { + + my $gid = $entry->get_value('gidNumber'); + my $dn = $entry->dn; + + my $local_res = $ldap->search( + base => $suffix, + filter => "(&(objectclass=posixGroup)(gidNumber=$gid))"); + + $local_res->code && die "failed to search: ", $local_res->error; + if ($local_res->count > 1) { + print "A PosixGroup with gidNumber [$gid] must exactly exist once\n"; + print "You have ", $local_res->count, " entries:\n"; + foreach my $loc_entry ($local_res->all_entries) { + printf "\t%s\n", $loc_entry->dn; + } + ++$bad_gids; + next; + } + + if ($check_local_files && exists $group_h{$gid}) { + print "Warning: There is a group in /etc/group that has gidNumber [$gid] as well\n"; + print "This entry may conflict with $dn\n"; + ++$bad_gids; + } +} + +if ($bad_gids) { + $ret = -1; + print "You have $bad_gids bad gidNumbers in your system. You might need to repair them\n"; +} else { + print "No multiple gidNumbers found in your system\n"; +} + +print "-" x 80, "\n"; + + +########################### +# check for double users # +########################### + +print "\ntesting for multiple uidNumbers\n"; + +$res = $ldap->search( + base => $suffix, + filter => "(objectclass=posixAccount)"); + +$res->code && die "failed to search: ", $res->error; + + +foreach my $entry ($res->all_entries) { + + my $uid = $entry->get_value('uidNumber'); + my $dn = $entry->dn; + + my $local_res = $ldap->search( + base => $suffix, + filter => "(&(objectclass=posixAccount)(uidNumber=$uid))"); + + $local_res->code && die "failed to search: ", $local_res->error; + if ($local_res->count > 1) { + print "A PosixAccount with uidNumber [$uid] must exactly exist once\n"; + print "You have ", $local_res->count, " entries:\n"; + foreach my $loc_entry ($local_res->all_entries) { + printf "\t%s\n", $loc_entry->dn; + } + ++$bad_uids; + next; + } + if ($check_local_files && exists $passwd_h{$uid}) { + print "Warning: There is a user in /etc/passwd that has uidNumber [$uid] as well\n"; + print "This entry may conflict with $dn\n"; + ++$bad_uids; + } +} + +if ($bad_uids) { + $ret = -1; + print "You have $bad_uids bad uidNumbers in your system. You might need to repair them\n"; +} else { + print "No multiple uidNumbers found in your system\n"; +} + +$ldap->unbind; + +exit $ret; diff --git a/examples/misc/cldap.pl b/examples/misc/cldap.pl new file mode 100755 index 0000000..c33fded --- /dev/null +++ b/examples/misc/cldap.pl @@ -0,0 +1,491 @@ +#!/usr/bin/perl -w + +# Copyright (C) Guenther Deschner <gd@samba.org> 2006 + +use strict; +use IO::Socket; +use Convert::ASN1 qw(:debug); +use Getopt::Long; + +# TODO: timeout handling, user CLDAP query + +################################## + +my $server = ""; +my $domain = ""; +my $host = ""; + +################################## + +my ( + $opt_debug, + $opt_domain, + $opt_help, + $opt_host, + $opt_server, +); + +my %cldap_flags = ( + ADS_PDC => 0x00000001, # DC is PDC + ADS_GC => 0x00000004, # DC is a GC of forest + ADS_LDAP => 0x00000008, # DC is an LDAP server + ADS_DS => 0x00000010, # DC supports DS + ADS_KDC => 0x00000020, # DC is running KDC + ADS_TIMESERV => 0x00000040, # DC is running time services + ADS_CLOSEST => 0x00000080, # DC is closest to client + ADS_WRITABLE => 0x00000100, # DC has writable DS + ADS_GOOD_TIMESERV => 0x00000200, # DC has hardware clock (and running time) + ADS_NDNC => 0x00000400, # DomainName is non-domain NC serviced by LDAP server +); + +my %cldap_samlogon_types = ( + SAMLOGON_AD_UNK_R => 23, + SAMLOGON_AD_R => 25, +); + +my $MAX_DNS_LABEL = 255 + 1; + +my %cldap_netlogon_reply = ( + type => 0, + flags => 0x0, + guid => 0, + forest => undef, + domain => undef, + hostname => undef, + netbios_domain => undef, + netbios_hostname => undef, + unk => undef, + user_name => undef, + server_site_name => undef, + client_site_name => undef, + version => 0, + lmnt_token => 0x0, + lm20_token => 0x0, +); + +sub usage { + print "usage: $0 [--domain|-d domain] [--help] [--host|-h host] [--server|-s server]\n\n"; +} + +sub connect_cldap ($) { + + my $server = shift || return undef; + + return IO::Socket::INET->new( + PeerAddr => $server, + PeerPort => 389, + Proto => 'udp', + Type => SOCK_DGRAM, + Timeout => 10, + ); +} + +sub send_cldap_netlogon ($$$$) { + + my ($sock, $domain, $host, $ntver) = @_; + + my $asn_cldap_req = Convert::ASN1->new; + + $asn_cldap_req->prepare(q< + + SEQUENCE { + msgid INTEGER, + [APPLICATION 3] SEQUENCE { + basedn OCTET STRING, + scope ENUMERATED, + dereference ENUMERATED, + sizelimit INTEGER, + timelimit INTEGER, + attronly BOOLEAN, + [CONTEXT 0] SEQUENCE { + [CONTEXT 3] SEQUENCE { + dnsdom_attr OCTET STRING, + dnsdom_val OCTET STRING + } + [CONTEXT 3] SEQUENCE { + host_attr OCTET STRING, + host_val OCTET STRING + } + [CONTEXT 3] SEQUENCE { + ntver_attr OCTET STRING, + ntver_val OCTET STRING + } + } + SEQUENCE { + netlogon OCTET STRING + } + } + } + >); + + my $pdu_req = $asn_cldap_req->encode( + msgid => 0, + basedn => "", + scope => 0, + dereference => 0, + sizelimit => 0, + timelimit => 0, + attronly => 0, + dnsdom_attr => $domain ? 'DnsDomain' : "", + dnsdom_val => $domain ? $domain : "", + host_attr => 'Host', + host_val => $host, + ntver_attr => 'NtVer', + ntver_val => $ntver, + netlogon => 'NetLogon', + ) || die "failed to encode pdu: $@"; + + if ($opt_debug) { + print"------------\n"; + asn_dump($pdu_req); + print"------------\n"; + } + + return $sock->send($pdu_req) || die "no send: $@"; +} + +# from source/libads/cldap.c : +# +#/* +# These seem to be strings as described in RFC1035 4.1.4 and can be: +# +# - a sequence of labels ending in a zero octet +# - a pointer +# - a sequence of labels ending with a pointer +# +# A label is a byte where the first two bits must be zero and the remaining +# bits represent the length of the label followed by the label itself. +# Therefore, the length of a label is at max 64 bytes. Under RFC1035, a +# sequence of labels cannot exceed 255 bytes. +# +# A pointer consists of a 14 bit offset from the beginning of the data. +# +# struct ptr { +# unsigned ident:2; // must be 11 +# unsigned offset:14; // from the beginning of data +# }; +# +# This is used as a method to compress the packet by eliminated duplicate +# domain components. Since a UDP packet should probably be < 512 bytes and a +# DNS name can be up to 255 bytes, this actually makes a lot of sense. +#*/ + +sub pull_netlogon_string (\$$$) { + + my ($ret, $ptr, $str) = @_; + + my $pos = $ptr; + + my $followed_ptr = 0; + my $ret_len = 0; + + my $retp = pack("x$MAX_DNS_LABEL"); + + do { + + $ptr = unpack("c", substr($str, $pos, 1)); + $pos++; + + if (($ptr & 0xc0) == 0xc0) { + + my $len; + + if (!$followed_ptr) { + $ret_len += 2; + $followed_ptr = 1; + } + + my $tmp0 = $ptr; #unpack("c", substr($str, $pos-1, 1)); + my $tmp1 = unpack("c", substr($str, $pos, 1)); + + if ($opt_debug) { + printf("tmp0: 0x%x\n", $tmp0); + printf("tmp1: 0x%x\n", $tmp1); + } + + $len = (($tmp0 & 0x3f) << 8) | $tmp1; + $ptr = unpack("c", substr($str, $len, 1)); + $pos = $len; + + } elsif ($ptr) { + + my $len = scalar $ptr; + + if ($len + 1 > $MAX_DNS_LABEL) { + warn("invalid string size: %d", $len + 1); + return 0; + } + + $ptr = unpack("a*", substr($str, $pos, $len)); + + $retp = sprintf("%s%s\.", $retp, $ptr); + + $pos += $len; + if (!$followed_ptr) { + $ret_len += $len + 1; + } + } + + } while ($ptr); + + $retp =~ s/\.$//; #ugly hack... + + $$ret = $retp; + + return $followed_ptr ? $ret_len : $ret_len + 1; +} + +sub dump_cldap_flags ($) { + + my $flags = shift || return; + printf("Flags:\n". + "\tIs a PDC: %s\n". + "\tIs a GC of the forest: %s\n". + "\tIs an LDAP server: %s\n". + "\tSupports DS: %s\n". + "\tIs running a KDC: %s\n". + "\tIs running time services: %s\n". + "\tIs the closest DC: %s\n". + "\tIs writable: %s\n". + "\tHas a hardware clock: %s\n". + "\tIs a non-domain NC serviced by LDAP server: %s\n", + ($flags & $cldap_flags{ADS_PDC}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_GC}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_LDAP}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_DS}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_KDC}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_TIMESERV}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_CLOSEST}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_WRITABLE}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_GOOD_TIMESERV}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_NDNC}) ? "yes" : "no"); +} + +sub guid_to_string ($) { + + my $guid = shift || return undef; + if ((my $len = length $guid) != 16) { + printf("invalid length: %d\n", $len); + return undef; + } + my $string = sprintf "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + unpack("I", $guid), + unpack("S", substr($guid, 4, 2)), + unpack("S", substr($guid, 6, 2)), + unpack("C", substr($guid, 8, 1)), + unpack("C", substr($guid, 9, 1)), + unpack("C", substr($guid, 10, 1)), + unpack("C", substr($guid, 11, 1)), + unpack("C", substr($guid, 12, 1)), + unpack("C", substr($guid, 13, 1)), + unpack("C", substr($guid, 14, 1)), + unpack("C", substr($guid, 15, 1)); + return lc($string); +} + +sub recv_cldap_netlogon ($\$) { + + my ($sock, $return_string) = @_; + my ($ret, $pdu_out); + + $ret = $sock->recv($pdu_out, 8192) || die "failed to read from socket: $@"; + #$ret = sysread($sock, $pdu_out, 8192); + + if ($opt_debug) { + print"------------\n"; + asn_dump($pdu_out); + print"------------\n"; + } + + my $asn_cldap_rep = Convert::ASN1->new; + my $asn_cldap_rep_fail = Convert::ASN1->new; + + $asn_cldap_rep->prepare(q< + SEQUENCE { + msgid INTEGER, + [APPLICATION 4] SEQUENCE { + dn OCTET STRING, + SEQUENCE { + SEQUENCE { + attr OCTET STRING, + SET { + val OCTET STRING + } + } + } + } + } + SEQUENCE { + msgid2 INTEGER, + [APPLICATION 5] SEQUENCE { + error_code ENUMERATED, + matched_dn OCTET STRING, + error_message OCTET STRING + } + } + >); + + $asn_cldap_rep_fail->prepare(q< + SEQUENCE { + msgid2 INTEGER, + [APPLICATION 5] SEQUENCE { + error_code ENUMERATED, + matched_dn OCTET STRING, + error_message OCTET STRING + } + } + >); + + my $asn1_rep = $asn_cldap_rep->decode($pdu_out) || + $asn_cldap_rep_fail->decode($pdu_out) || + die "failed to decode pdu: $@"; + + if ($asn1_rep->{'error_code'} == 0) { + $$return_string = $asn1_rep->{'val'}; + } + + return $ret; +} + +sub parse_cldap_reply ($) { + + my $str = shift || return undef; + my %hash; + my $p = 0; + + $hash{type} = unpack("L", substr($str, $p, 4)); $p += 4; + $hash{flags} = unpack("L", substr($str, $p, 4)); $p += 4; + $hash{guid} = unpack("a16", substr($str, $p, 16)); $p += 16; + + $p += pull_netlogon_string($hash{forest}, $p, $str); + $p += pull_netlogon_string($hash{domain}, $p, $str); + $p += pull_netlogon_string($hash{hostname}, $p, $str); + $p += pull_netlogon_string($hash{netbios_domain}, $p, $str); + $p += pull_netlogon_string($hash{netbios_hostname}, $p, $str); + $p += pull_netlogon_string($hash{unk}, $p, $str); + + if ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_R}) { + $p += pull_netlogon_string($hash{user_name}, $p, $str); + } else { + $hash{user_name} = ""; + } + + $p += pull_netlogon_string($hash{server_site_name}, $p, $str); + $p += pull_netlogon_string($hash{client_site_name}, $p, $str); + + $hash{version} = unpack("L", substr($str, $p, 4)); $p += 4; + $hash{lmnt_token} = unpack("S", substr($str, $p, 2)); $p += 2; + $hash{lm20_token} = unpack("S", substr($str, $p, 2)); $p += 2; + + return %hash; +} + +sub display_cldap_reply { + + my $server = shift; + my (%hash) = @_; + + my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($server); + + printf("Information for Domain Controller: %s\n\n", $name); + + printf("Response Type: "); + if ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_R}) { + printf("SAMLOGON_USER\n"); + } elsif ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_UNK_R}) { + printf("SAMLOGON\n"); + } else { + printf("unknown type 0x%x, please report\n", $hash{type}); + } + + # guid + printf("GUID: %s\n", guid_to_string($hash{guid})); + + # flags + dump_cldap_flags($hash{flags}); + + # strings + printf("Forest:\t\t\t%s\n", $hash{forest}); + printf("Domain:\t\t\t%s\n", $hash{domain}); + printf("Domain Controller:\t%s\n", $hash{hostname}); + + printf("Pre-Win2k Domain:\t%s\n", $hash{netbios_domain}); + printf("Pre-Win2k Hostname:\t%s\n", $hash{netbios_hostname}); + + if ($hash{unk}) { + printf("Unk:\t\t\t%s\n", $hash{unk}); + } + if ($hash{user_name}) { + printf("User name:\t%s\n", $hash{user_name}); + } + + printf("Server Site Name:\t%s\n", $hash{server_site_name}); + printf("Client Site Name:\t%s\n", $hash{client_site_name}); + + # some more int + printf("NT Version:\t\t%d\n", $hash{version}); + printf("LMNT Token:\t\t%.2x\n", $hash{lmnt_token}); + printf("LM20 Token:\t\t%.2x\n", $hash{lm20_token}); +} + +sub main() { + + my ($ret, $sock, $reply); + + GetOptions( + 'debug' => \$opt_debug, + 'domain|d=s' => \$opt_domain, + 'help' => \$opt_help, + 'host|h=s' => \$opt_host, + 'server|s=s' => \$opt_server, + ); + + $server = $server || $opt_server; + $domain = $domain || $opt_domain || undef; + $host = $host || $opt_host; + if (!$host) { + $host = `/bin/hostname`; + chomp($host); + } + + if (!$server || !$host || $opt_help) { + usage(); + exit 1; + } + + my $ntver = sprintf("%c%c%c%c", 6,0,0,0); + + $sock = connect_cldap($server); + if (!$sock) { + die("could not connect to $server"); + } + + $ret = send_cldap_netlogon($sock, $domain, $host, $ntver); + if (!$ret) { + close($sock); + die("failed to send CLDAP request to $server"); + } + + $ret = recv_cldap_netlogon($sock, $reply); + if (!$ret) { + close($sock); + die("failed to receive CLDAP reply from $server"); + } + close($sock); + + if (!$reply) { + printf("no 'NetLogon' attribute received\n"); + exit 0; + } + + %cldap_netlogon_reply = parse_cldap_reply($reply); + if (!%cldap_netlogon_reply) { + die("failed to parse CLDAP reply from $server"); + } + + display_cldap_reply($server, %cldap_netlogon_reply); + + exit 0; +} + +main(); diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus new file mode 100644 index 0000000..7f77d07 --- /dev/null +++ b/examples/misc/extra_smbstatus @@ -0,0 +1,50 @@ +Here's something that Paul Blackman sent me that may be useful: + +------------------- +I created this script to do a few things that smbstatus doesn't at the +moment. Perhaps you might want to include these. Sorry I haven't +added things at source level, script was quick&easy. + +******* +#!/bin/csh +if ($1 == "-p") then + smbstatus -p |sort -u +else if ($1 == "-c") then + echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique smbd processes running. + else if ($1 == "-l") then + echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z |grep -c :` >>$2 +else if ($1 == "-cs") then + echo There are `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` concurrent connections to share: $2 +else if ($1 == "-csl") then + echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` >>$3 +else + echo "'smbstat -c' ==> Count unique smbd processes." + echo "'smbstat -p' ==> List unique smbd processes." + echo "'smbstat -l logfile' ==> Append a log entry for the number of" + echo " concurrent and unique processes to logfile." + echo "'smbstat -cs sharename'" + echo " ==> Count processes connected to sharename (assumed unique)" + echo "'smbstat -csl sharename logfile'" + echo " ==> Append a log entry for the number of concurrent" + echo " processes connected to sharename (assumed unique)" +endif +****** + +Run this script from cron eg. + +0,5,10,15,20,25,30,35,40,50,55 * * * * /usr/local/samba/bin/smbstat -l /usr/local/samba/var/smbdcount.log + +and you get a good idea of usage over time. + +Cheers, +~^ MIME OK ^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~ + o | Paul Blackman ictinus@lake.canberra.edu.au + o | Co-operative Research ------------------------ + o _ | Centre For Freshwater Ecology. Ph. (Aus) 06 2012518 + -- (") o | University of Canberra, Australia. Fax. " 06 2015038 + \_|_-- |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | "Spend a little love and get high" + _/ \_ | - Lenny Kravitz +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~ SAMBA Web Pages: http://samba.org/samba/ ~~~~~~~~~~~~~~ + diff --git a/examples/misc/wall.perl b/examples/misc/wall.perl new file mode 100644 index 0000000..efa4ee5 --- /dev/null +++ b/examples/misc/wall.perl @@ -0,0 +1,69 @@ +#! /usr/bin/env perl +# +#@(#) smb-wall.pl Description: +#@(#) A perl script which allows you to announce whatever you choose to +#@(#) every PC client currently connected to a Samba Server... +#@(#) ...using "smbclient -M" message to winpopup service. +#@(#) Default usage is to message every connected PC. +#@(#) Alternate usage is to message every pc on the argument list. +#@(#) Hacked up by Keith Farrar <farrar@parc.xerox.com> +# +# Cleanup and corrections by +# Michal Jaegermann <michal@ellpspace.math.ualberta.ca> +# Message to send can be now also fed (quietly) from stdin; a pipe will do. +#============================================================================= + +$smbstatus = "/usr/local/bin/smbstatus"; +$smbshout = "/usr/local/bin/smbclient -M"; + +if (@ARGV) { + @clients = @ARGV; + undef @ARGV; +} +else { # no clients specified explicitly + open(PCLIST, "$smbstatus |") || die "$smbstatus failed!.\n$!\n"; + while(<PCLIST>) { + last if /^Locked files:/; + split(' ', $_, 6); + # do not accept this line if less then six fields + next unless $_[5]; + # if you have A LOT of clients you may speed things up by + # checking pid - no need to look further if this pid was already + # seen; left as an exercise :-) + $client = $_[4]; + next unless $client =~ /^\w+\./; # expect 'dot' in a client name + next if grep($_ eq $client, @clients); # we want this name once + push(@clients, $client); + } + close(PCLIST); +} + +if (-t) { + print <<'EOT'; + +Enter message for Samba clients of this host +(terminated with single '.' or end of file): +EOT + + while (<>) { + last if /^\.$/; + push(@message, $_); + } +} +else { # keep quiet and read message from stdin + @message = <>; +} + +foreach(@clients) { +## print "To $_:\n"; + if (open(SENDMSG,"|$smbshout $_")) { + print SENDMSG @message; + close(SENDMSG); + } + else { + warn "Cannot notify $_ with $smbshout:\n$!\n"; + } +} + +exit 0; + diff --git a/examples/nss/nss_winbind.c b/examples/nss/nss_winbind.c new file mode 100644 index 0000000..968cc7a --- /dev/null +++ b/examples/nss/nss_winbind.c @@ -0,0 +1,422 @@ +/* + nss sample code for extended winbindd functionality + + Copyright (C) Andrew Tridgell (tridge@samba.org) + + you are free to use this code in any way you see fit, including + without restriction, using this code in your own products. You do + not need to give any attribution. +*/ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <nss.h> +#include <dlfcn.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> + +#include "nss_winbind.h" + +/* + find a function in the nss library +*/ +static void *find_fn(struct nss_state *nss, const char *name) +{ + void *res; + char *s = NULL; + + asprintf(&s, "_nss_%s_%s", nss->nss_name, name); + if (!s) { + errno = ENOMEM; + return NULL; + } + res = dlsym(nss->dl_handle, s); + free(s); + if (!res) { + errno = ENOENT; + return NULL; + } + return res; +} + +/* + establish a link to the nss library + Return 0 on success and -1 on error +*/ +int nss_open(struct nss_state *nss, const char *nss_path) +{ + char *p; + p = strrchr(nss_path, '_'); + if (!p) { + errno = EINVAL; + return -1; + } + + nss->nss_name = strdup(p+1); + p = strchr(nss->nss_name, '.'); + if (p) *p = 0; + + nss->dl_handle = dlopen(nss_path, RTLD_LAZY); + if (!nss->dl_handle) { + free(nss->nss_name); + return -1; + } + + return 0; +} + +/* + close and cleanup a nss state +*/ +void nss_close(struct nss_state *nss) +{ + free(nss->nss_name); + dlclose(nss->dl_handle); +} + +/* + make a getpwnam call. + Return 0 on success and -1 on error +*/ +int nss_getpwent(struct nss_state *nss, struct passwd *pwd) +{ + enum nss_status (*_nss_getpwent_r)(struct passwd *, char *, + size_t , int *); + enum nss_status status; + int nss_errno = 0; + + _nss_getpwent_r = find_fn(nss, "getpwent_r"); + + if (!_nss_getpwent_r) { + return -1; + } + + status = _nss_getpwent_r(pwd, nss->pwnam_buf, sizeof(nss->pwnam_buf), + &nss_errno); + if (status == NSS_STATUS_NOTFOUND) { + errno = ENOENT; + return -1; + } + if (status != NSS_STATUS_SUCCESS) { + errno = nss_errno; + return -1; + } + + return 0; +} + +/* + make a setpwent call. + Return 0 on success and -1 on error +*/ +int nss_setpwent(struct nss_state *nss) +{ + enum nss_status (*_nss_setpwent)(void) = find_fn(nss, "setpwent"); + enum nss_status status; + if (!_nss_setpwent) { + return -1; + } + status = _nss_setpwent(); + if (status != NSS_STATUS_SUCCESS) { + errno = EINVAL; + return -1; + } + return 0; +} + +/* + make a endpwent call. + Return 0 on success and -1 on error +*/ +int nss_endpwent(struct nss_state *nss) +{ + enum nss_status (*_nss_endpwent)(void) = find_fn(nss, "endpwent"); + enum nss_status status; + if (!_nss_endpwent) { + return -1; + } + status = _nss_endpwent(); + if (status != NSS_STATUS_SUCCESS) { + errno = EINVAL; + return -1; + } + return 0; +} + + +/* + convert a name to a SID + caller frees + Return 0 on success and -1 on error +*/ +int nss_nametosid(struct nss_state *nss, const char *name, char **sid) +{ + enum nss_status (*_nss_nametosid)(const char *, char **, char *, + size_t, int *); + enum nss_status status; + int nss_errno = 0; + char buf[200]; + + _nss_nametosid = find_fn(nss, "nametosid"); + + if (!_nss_nametosid) { + return -1; + } + + status = _nss_nametosid(name, sid, buf, sizeof(buf), &nss_errno); + if (status == NSS_STATUS_NOTFOUND) { + errno = ENOENT; + return -1; + } + if (status != NSS_STATUS_SUCCESS) { + errno = nss_errno; + return -1; + } + + *sid = strdup(*sid); + + return 0; +} + +/* + convert a SID to a name + caller frees + Return 0 on success and -1 on error +*/ +int nss_sidtoname(struct nss_state *nss, const char *sid, char **name) +{ + enum nss_status (*_nss_sidtoname)(const char *, char **, char *, + size_t, int *); + enum nss_status status; + int nss_errno = 0; + char buf[200]; + + _nss_sidtoname = find_fn(nss, "sidtoname"); + + if (!_nss_sidtoname) { + return -1; + } + + status = _nss_sidtoname(sid, name, buf, sizeof(buf), &nss_errno); + if (status == NSS_STATUS_NOTFOUND) { + errno = ENOENT; + return -1; + } + if (status != NSS_STATUS_SUCCESS) { + errno = nss_errno; + return -1; + } + + *name = strdup(*name); + + return 0; +} + +/* + return a list of group SIDs for a user SID + the returned list is NULL terminated + Return 0 on success and -1 on error +*/ +int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids) +{ + enum nss_status (*_nss_getusersids)(const char *, char **, int *, + char *, size_t, int *); + enum nss_status status; + int nss_errno = 0; + char *s; + int i, num_groups = 0; + unsigned bufsize = 10; + char *buf; + + _nss_getusersids = find_fn(nss, "getusersids"); + + if (!_nss_getusersids) { + return -1; + } + +again: + buf = malloc(bufsize); + if (!buf) { + errno = ENOMEM; + return -1; + } + + status = _nss_getusersids(user_sid, &s, &num_groups, buf, bufsize, + &nss_errno); + + if (status == NSS_STATUS_NOTFOUND) { + errno = ENOENT; + free(buf); + return -1; + } + + if (status == NSS_STATUS_TRYAGAIN) { + bufsize *= 2; + free(buf); + goto again; + } + + if (status != NSS_STATUS_SUCCESS) { + free(buf); + errno = nss_errno; + return -1; + } + + if (num_groups == 0) { + free(buf); + return 0; + } + + *sids = (char **)malloc(sizeof(char *) * (num_groups+1)); + if (! *sids) { + errno = ENOMEM; + free(buf); + return -1; + } + + for (i=0;i<num_groups;i++) { + (*sids)[i] = strdup(s); + s += strlen(s) + 1; + } + (*sids)[i] = NULL; + + free(buf); + + return 0; +} + +/* + convert a sid to a uid + Return 0 on success and -1 on error +*/ +int nss_sidtouid(struct nss_state *nss, const char *sid, uid_t *uid) +{ + enum nss_status (*_nss_sidtouid)(const char*, uid_t *, int*); + + enum nss_status status; + int nss_errno = 0; + + _nss_sidtouid = find_fn(nss, "sidtouid"); + + if (!_nss_sidtouid) { + return -1; + } + + status = _nss_sidtouid(sid, uid, &nss_errno); + + if (status == NSS_STATUS_NOTFOUND) { + errno = ENOENT; + return -1; + } + + if (status != NSS_STATUS_SUCCESS) { + errno = nss_errno; + return -1; + } + + return 0; +} + +/* + convert a sid to a gid + Return 0 on success and -1 on error +*/ +int nss_sidtogid(struct nss_state *nss, const char *sid, gid_t *gid) +{ + enum nss_status (*_nss_sidtogid)(const char*, gid_t *, int*); + + enum nss_status status; + int nss_errno = 0; + + _nss_sidtogid = find_fn(nss, "sidtogid"); + + if (!_nss_sidtogid) { + return -1; + } + + status = _nss_sidtogid(sid, gid, &nss_errno); + + if (status == NSS_STATUS_NOTFOUND) { + errno = ENOENT; + return -1; + } + + if (status != NSS_STATUS_SUCCESS) { + errno = nss_errno; + return -1; + } + + return 0; +} + +/* + convert a uid to a sid + caller frees + Return 0 on success and -1 on error +*/ +int nss_uidtosid(struct nss_state *nss, uid_t uid, char **sid) +{ + enum nss_status (*_nss_uidtosid)(uid_t, char **, char *, + size_t, int *); + enum nss_status status; + int nss_errno = 0; + char buf[200]; + + _nss_uidtosid = find_fn(nss, "uidtosid"); + + if (!_nss_uidtosid) { + return -1; + } + + status = _nss_uidtosid(uid, sid, buf, sizeof(buf), &nss_errno); + if (status == NSS_STATUS_NOTFOUND) { + errno = ENOENT; + return -1; + } + if (status != NSS_STATUS_SUCCESS) { + errno = nss_errno; + return -1; + } + + *sid = strdup(*sid); + + return 0; +} + +/* + convert a gid to a sid + caller frees + Return 0 on success and -1 on error +*/ +int nss_gidtosid(struct nss_state *nss, gid_t gid, char **sid) +{ + enum nss_status (*_nss_gidtosid)(gid_t, char **, char *, + size_t, int *); + enum nss_status status; + int nss_errno = 0; + char buf[200]; + + _nss_gidtosid = find_fn(nss, "gidtosid"); + + if (!_nss_gidtosid) { + return -1; + } + + status = _nss_gidtosid(gid, sid, buf, sizeof(buf), &nss_errno); + if (status == NSS_STATUS_NOTFOUND) { + errno = ENOENT; + return -1; + } + if (status != NSS_STATUS_SUCCESS) { + errno = nss_errno; + return -1; + } + + *sid = strdup(*sid); + + return 0; +} + diff --git a/examples/nss/nss_winbind.h b/examples/nss/nss_winbind.h new file mode 100644 index 0000000..5a124a5 --- /dev/null +++ b/examples/nss/nss_winbind.h @@ -0,0 +1,97 @@ +/* + nss sample code for extended winbindd functionality + + Copyright (C) Andrew Tridgell (tridge@samba.org) + Copyright (C) Volker Lendecke (vl@samba.org) + + you are free to use this code in any way you see fit, including + without restriction, using this code in your own products. You do + not need to give any attribution. +*/ + +#define _GNU_SOURCE + +#include <pwd.h> +#include <grp.h> + +struct nss_state { + void *dl_handle; + char *nss_name; + char pwnam_buf[512]; +}; + +/* + establish a link to the nss library + Return 0 on success and -1 on error +*/ +int nss_open(struct nss_state *nss, const char *nss_path); + +/* + close and cleanup a nss state +*/ +void nss_close(struct nss_state *nss); + +/* + make a getpwnam call. + Return 0 on success and -1 on error +*/ +int nss_getpwent(struct nss_state *nss, struct passwd *pwd); + +/* + make a setpwent call. + Return 0 on success and -1 on error +*/ +int nss_setpwent(struct nss_state *nss); + +/* + make a endpwent call. + Return 0 on success and -1 on error +*/ +int nss_endpwent(struct nss_state *nss); + +/* + convert a name to a SID + caller frees + Return 0 on success and -1 on error +*/ +int nss_nametosid(struct nss_state *nss, const char *name, char **sid); + +/* + convert a SID to a name + caller frees + Return 0 on success and -1 on error +*/ +int nss_sidtoname(struct nss_state *nss, const char *sid, char **name); + +/* + return a list of group SIDs for a user SID + the returned list is NULL terminated + Return 0 on success and -1 on error +*/ +int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids); + +/* + convert a sid to a uid + Return 0 on success and -1 on error +*/ +int nss_sidtouid(struct nss_state *nss, const char *sid, uid_t *uid); + +/* + convert a sid to a gid + Return 0 on success and -1 on error +*/ +int nss_sidtogid(struct nss_state *nss, const char *sid, gid_t *gid); + +/* + convert a uid to a sid + caller frees + Return 0 on success and -1 on error +*/ +int nss_uidtosid(struct nss_state *nss, uid_t uid, char **sid); + +/* + convert a gid to a sid + caller frees + Return 0 on success and -1 on error +*/ +int nss_gidtosid(struct nss_state *nss, gid_t gid, char **sid); diff --git a/examples/nss/wbtest.c b/examples/nss/wbtest.c new file mode 100644 index 0000000..14265bd --- /dev/null +++ b/examples/nss/wbtest.c @@ -0,0 +1,111 @@ +/* + nss sample code for extended winbindd functionality + + Copyright (C) Andrew Tridgell (tridge@samba.org) + + you are free to use this code in any way you see fit, including + without restriction, using this code in your own products. You do + not need to give any attribution. +*/ + +/* + compile like this: + + cc -o wbtest wbtest.c nss_winbind.c -ldl + + and run like this: + + ./wbtest /lib/libnss_winbind.so +*/ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <nss.h> +#include <dlfcn.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> + +#include "nss_winbind.h" + +static int nss_test_users(struct nss_state *nss) +{ + struct passwd pwd; + + if (nss_setpwent(nss) != 0) { + perror("setpwent"); + return -1; + } + + /* loop over all users */ + while ((nss_getpwent(nss, &pwd) == 0)) { + char *sid, **group_sids, *name2; + int i; + + printf("User %s\n", pwd.pw_name); + if (nss_nametosid(nss, pwd.pw_name, &sid) != 0) { + perror("nametosid"); + return -1; + } + printf("\tSID %s\n", sid); + + if (nss_sidtoname(nss, sid, &name2) != 0) { + perror("sidtoname"); + return -1; + } + printf("\tSID->name %s\n", name2); + + if (nss_getusersids(nss, sid, &group_sids) != 0) { + perror("getusersids"); + return -1; + } + + printf("\tGroups:\n"); + for (i=0; group_sids[i]; i++) { + printf("\t\t%s\n", group_sids[i]); + free(group_sids[i]); + } + + free(sid); + free(name2); + free(group_sids); + } + + + if (nss_endpwent(nss) != 0) { + perror("endpwent"); + return -1; + } + + return 0; +} + + +/* + main program. It lists all users, listing user SIDs for each user + */ +int main(int argc, char *argv[]) +{ + struct nss_state nss; + const char *so_path = "/lib/libnss_winbind.so"; + int ret; + + if (argc > 1) { + so_path = argv[1]; + } + + if (nss_open(&nss, so_path) != 0) { + perror("nss_open"); + exit(1); + } + + ret = nss_test_users(&nss); + + nss_close(&nss); + + return ret; +} diff --git a/examples/pam_winbind/pam_winbind.conf b/examples/pam_winbind/pam_winbind.conf new file mode 100644 index 0000000..85cd513 --- /dev/null +++ b/examples/pam_winbind/pam_winbind.conf @@ -0,0 +1,39 @@ +# +# pam_winbind configuration file +# +# /etc/security/pam_winbind.conf +# +# For more details see man pam_winbind.conf(5) + +[global] + +# turn on debugging +;debug = no + +# turn on extended PAM state debugging +;debug_state = no + +# request a cached login if possible +# (needs "winbind offline logon = yes" in smb.conf) +;cached_login = no + +# authenticate using kerberos +;krb5_auth = no + +# when using kerberos, request a "FILE" or "DIR" krb5 credential cache type +# (leave empty to just do krb5 authentication but not have a ticket +# afterwards) +;krb5_ccache_type = + +# make successful authentication dependent on membership of one SID +# (can also take a name) +;require_membership_of = + +# password expiry warning period in days +;warn_pwd_expire = 14 + +# omit pam conversations +;silent = no + +# create homedirectory on the fly +;mkhomedir = no diff --git a/examples/pcap2nbench/COPYING b/examples/pcap2nbench/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/examples/pcap2nbench/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/examples/pcap2nbench/Makefile b/examples/pcap2nbench/Makefile new file mode 100644 index 0000000..c1221b3 --- /dev/null +++ b/examples/pcap2nbench/Makefile @@ -0,0 +1,33 @@ +############################################################################### +## +## pcap2nbench - Converts libpcap network traces to nbench input +## Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## +## Written by Anthony Liguori <aliguori@us.ibm.com> +## +############################################################################### + +OBJ=main.o ethernet.o ip.o tcp.o smb.o ntcreateandxrequest.o readandxrequest.o writeandxrequest.o closerequest.o ntcreateandxresponse.o +PROG=pcap2nbench +CXXFLAGS=-g -Wall +LDFLAGS= +LIB=-lpcap + +$(PROG): $(OBJ) + $(CXX) -o $(PROG) $(CXXFLAGS) $(OBJ) $(LDFLAGS) $(LIB) + +clean: + $(RM) $(OBJ) $(PROG) diff --git a/examples/pcap2nbench/README b/examples/pcap2nbench/README new file mode 100644 index 0000000..09c30e0 --- /dev/null +++ b/examples/pcap2nbench/README @@ -0,0 +1,24 @@ +pcap2nbench +----------- + +About + +This program converts a libpcap network trace file (produced by ethereal or +another pcap-aware network analyzer) into a output suitable for nbench. The +only option it takes is -i which suppresses any reads/writes/closes that use a +FID that does not have a corresponding ntcreateandx + +Limitations + +1) pcap2nbench does not handle ip fragmentation. You should not normally see + very much fragmentation so this should not really affect a workload. +2) unicode on the wire is not supported. +3) only a limited number of SMBs are supported. Namely: NtCreateAndX, + ReadAndX, WriteAndX, and Close. In addition, not all WCTs are supported on + each of these SMBs. + +Future Work + +It would be nice to use Samba or Ethereal's parsing code to handle the SMBs. +At first glance, this seemed non-trivial. It would also be nice to handle some +Trans2 SMBs specifically QueryFileInfo and QueryPathInfo. diff --git a/examples/pcap2nbench/closerequest.cpp b/examples/pcap2nbench/closerequest.cpp new file mode 100644 index 0000000..b31a1b6 --- /dev/null +++ b/examples/pcap2nbench/closerequest.cpp @@ -0,0 +1,45 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> + +#include "closerequest.hpp" + +CloseRequest::CloseRequest(const uint8_t *data, size_t size) +{ + if (size < 9) { + std::cerr << "Invalid Close Request" << std::endl; + return; + } + + word_count = data[0]; + memcpy(&fid, data + 1, 2); + memcpy(&last_write, data + 3, 4); + memcpy(&byte_count, data + 7, 2); +} + +std::ostream &operator<<(std::ostream &lhs, const CloseRequest &rhs) +{ + lhs << "Word Count: " << (uint16_t)rhs.word_count << std::endl + << "Fid: " << rhs.fid << std::endl + << "Last Write: " << rhs.last_write << std::endl + << "Byte Count: " << rhs.byte_count << std::endl; + return lhs; +} diff --git a/examples/pcap2nbench/closerequest.hpp b/examples/pcap2nbench/closerequest.hpp new file mode 100644 index 0000000..fe8866f --- /dev/null +++ b/examples/pcap2nbench/closerequest.hpp @@ -0,0 +1,43 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef _CLOSE_REQUEST_HPP +#define _CLOSE_REQUEST_HPP + +#include <iostream> +#include <stdint.h> + +struct CloseRequest { + enum { + COMMAND = 0x04 + }; + + CloseRequest() {} + CloseRequest(const uint8_t *data, size_t size); + + uint8_t word_count; + uint16_t fid; + uint32_t last_write; + uint16_t byte_count; +}; + +std::ostream &operator<<(std::ostream &lhs, const CloseRequest &rhs); + +#endif diff --git a/examples/pcap2nbench/ethernet.cpp b/examples/pcap2nbench/ethernet.cpp new file mode 100644 index 0000000..4d53159 --- /dev/null +++ b/examples/pcap2nbench/ethernet.cpp @@ -0,0 +1,61 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> + +#include "ethernet.hpp" + +ethernet::ethernet(const uint8_t *data, size_t length) { + if (length < 14) { + std::cerr << "Invalid ethernet packet" << std::endl; + } + memcpy(dst, data, sizeof(dst)); + memcpy(src, data + 6, sizeof(src)); + memcpy(&type, data + 12, sizeof(type)); + type = ntohs(type); +} + +std::ostream &operator<<(std::ostream &lhs, const ethernet &rhs) +{ + lhs << "Destination: "; + for (int i = 0; i < 6; i++) { + char buf[3]; + sprintf(buf, "%.2x", rhs.dst[i]); + if (i) lhs << ":"; + lhs << buf; + } + lhs << std::endl; + + lhs << "Source: "; + for (int i = 0; i < 6; i++) { + char buf[3]; + sprintf(buf, "%.2x", rhs.src[i]); + if (i) lhs << ":"; + lhs << buf; + } + lhs << std::endl; + + lhs << "Type: "; + char buf[7]; + sprintf(buf, "%.4x", rhs.type); + lhs << buf << std::endl; + + return lhs; +} diff --git a/examples/pcap2nbench/ethernet.hpp b/examples/pcap2nbench/ethernet.hpp new file mode 100644 index 0000000..baaca5a --- /dev/null +++ b/examples/pcap2nbench/ethernet.hpp @@ -0,0 +1,36 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef ETHERNET_HPP +#define ETHERNET_HPP + +#include <stdint.h> +#include <iostream> + +struct ethernet { + ethernet(const uint8_t *data, size_t length); + uint8_t dst[6]; + uint8_t src[6]; + uint16_t type; +}; + +std::ostream &operator<<(std::ostream &lhs, const ethernet &rhs); + +#endif diff --git a/examples/pcap2nbench/ip.cpp b/examples/pcap2nbench/ip.cpp new file mode 100644 index 0000000..8f1d821 --- /dev/null +++ b/examples/pcap2nbench/ip.cpp @@ -0,0 +1,65 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include "ip.hpp" + +ip::ip(const uint8_t *data, size_t length) +{ + if (length < 20) { + std::cerr << "Invalid ip packet" << std::endl; + } + + version = (data[0] >> 4) & 0x0F; + header_length = (data[0] & 0x0F) * 4; + dsfield = data[1]; + memcpy(&total_length, data + 2, 2); + total_length = ntohs(total_length); + memcpy(&id, data + 4, 2); + id = ntohs(id); + flags = (data[6] >> 4) & 0x0F; + fragment_offset = ((data[6] & 0x0F) << 4) | data[7]; + ttl = data[8]; + protocol = data[9]; + memcpy(&checksum, data + 10, 2); + checksum = ntohs(checksum); + memcpy(&source, data + 12, 4); + memcpy(&destination, data + 16, 4); +} + +std::ostream &operator<<(std::ostream &lhs, const ip &rhs) +{ + lhs << "Version: " << (uint32_t)rhs.version << std::endl + << "Header length: " << (uint32_t)rhs.header_length << std::endl + << "Differentiated Services Field: " << (uint32_t)rhs.dsfield << std::endl + << "Total Length: " << (uint32_t)rhs.total_length << std::endl + << "Identification: " << (uint32_t)rhs.id << std::endl + << "Flags: " << (uint32_t)rhs.flags << std::endl + << "Fragment offset: " << (uint32_t)rhs.fragment_offset << std::endl + << "TTL: " << (uint32_t)rhs.ttl << std::endl + << "Protocol: " << (uint32_t)rhs.protocol << std::endl + << "Checksum: " << (uint32_t)rhs.checksum << std::endl + << "Source: " << inet_ntoa(*((in_addr *)&rhs.source)) << std::endl + << "Destination: " << inet_ntoa(*((in_addr *)&rhs.destination)) << std::endl; + + return lhs; +} diff --git a/examples/pcap2nbench/ip.hpp b/examples/pcap2nbench/ip.hpp new file mode 100644 index 0000000..da1f0d3 --- /dev/null +++ b/examples/pcap2nbench/ip.hpp @@ -0,0 +1,46 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef IP_HPP +#define IP_HPP + +#include <stdint.h> +#include <iostream> + +struct ip { + ip(const uint8_t *data, size_t length); + + uint8_t version; + uint8_t header_length; + uint8_t dsfield; + uint16_t total_length; + uint16_t id; + uint8_t flags; + uint16_t fragment_offset; + uint8_t ttl; + uint8_t protocol; + uint16_t checksum; + uint32_t source; + uint32_t destination; +}; + +std::ostream &operator<<(std::ostream &lhs, const ip &rhs); + +#endif diff --git a/examples/pcap2nbench/main.cpp b/examples/pcap2nbench/main.cpp new file mode 100644 index 0000000..e07b473 --- /dev/null +++ b/examples/pcap2nbench/main.cpp @@ -0,0 +1,738 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <iostream> +#include <pcap.h> +#include <getopt.h> +#include <stdint.h> +#include <netinet/in.h> + +#include "ethernet.hpp" +#include "ip.hpp" +#include "tcp.hpp" +#include "smb.hpp" +#include "ntcreateandxrequest.hpp" +#include "ntcreateandxresponse.hpp" +#include "readandxrequest.hpp" +#include "writeandxrequest.hpp" +#include "closerequest.hpp" + +#include <vector> +#include <set> + + +/* derived from source/include/nterr.h */ +const char *nt_status_to_string[] = { + "NT_STATUS_OK", /* 0x0000 */ + "NT_STATUS_UNSUCCESSFUL", /* 0x0001 */ + "NT_STATUS_NOT_IMPLEMENTED", /* 0x0002 */ + "NT_STATUS_INVALID_INFO_CLASS", /* 0x0003 */ + "NT_STATUS_INFO_LENGTH_MISMATCH", /* 0x0004 */ + "NT_STATUS_ACCESS_VIOLATION", /* 0x0005 */ + "NT_STATUS_IN_PAGE_ERROR", /* 0x0006 */ + "NT_STATUS_PAGEFILE_QUOTA", /* 0x0007 */ + "NT_STATUS_INVALID_HANDLE", /* 0x0008 */ + "NT_STATUS_BAD_INITIAL_STACK", /* 0x0009 */ + "NT_STATUS_BAD_INITIAL_PC", /* 0x000a */ + "NT_STATUS_INVALID_CID", /* 0x000b */ + "NT_STATUS_TIMER_NOT_CANCELED", /* 0x000c */ + "NT_STATUS_INVALID_PARAMETER", /* 0x000d */ + "NT_STATUS_NO_SUCH_DEVICE", /* 0x000e */ + "NT_STATUS_NO_SUCH_FILE", /* 0x000f */ + "NT_STATUS_INVALID_DEVICE_REQUEST", /* 0x0010 */ + "NT_STATUS_END_OF_FILE", /* 0x0011 */ + "NT_STATUS_WRONG_VOLUME", /* 0x0012 */ + "NT_STATUS_NO_MEDIA_IN_DEVICE", /* 0x0013 */ + "NT_STATUS_UNRECOGNIZED_MEDIA", /* 0x0014 */ + "NT_STATUS_NONEXISTENT_SECTOR", /* 0x0015 */ + "NT_STATUS_MORE_PROCESSING_REQUIRED", /* 0x0016 */ + "NT_STATUS_NO_MEMORY", /* 0x0017 */ + "NT_STATUS_CONFLICTING_ADDRESSES", /* 0x0018 */ + "NT_STATUS_NOT_MAPPED_VIEW", /* 0x0019 */ + "NT_STATUS_UNABLE_TO_FREE_VM", /* 0x001a */ + "NT_STATUS_UNABLE_TO_DELETE_SECTION", /* 0x001b */ + "NT_STATUS_INVALID_SYSTEM_SERVICE", /* 0x001c */ + "NT_STATUS_ILLEGAL_INSTRUCTION", /* 0x001d */ + "NT_STATUS_INVALID_LOCK_SEQUENCE", /* 0x001e */ + "NT_STATUS_INVALID_VIEW_SIZE", /* 0x001f */ + "NT_STATUS_INVALID_FILE_FOR_SECTION", /* 0x0020 */ + "NT_STATUS_ALREADY_COMMITTED", /* 0x0021 */ + "NT_STATUS_ACCESS_DENIED", /* 0x0022 */ + "NT_STATUS_BUFFER_TOO_SMALL", /* 0x0023 */ + "NT_STATUS_OBJECT_TYPE_MISMATCH", /* 0x0024 */ + "NT_STATUS_NONCONTINUABLE_EXCEPTION", /* 0x0025 */ + "NT_STATUS_INVALID_DISPOSITION", /* 0x0026 */ + "NT_STATUS_UNWIND", /* 0x0027 */ + "NT_STATUS_BAD_STACK", /* 0x0028 */ + "NT_STATUS_INVALID_UNWIND_TARGET", /* 0x0029 */ + "NT_STATUS_NOT_LOCKED", /* 0x002a */ + "NT_STATUS_PARITY_ERROR", /* 0x002b */ + "NT_STATUS_UNABLE_TO_DECOMMIT_VM", /* 0x002c */ + "NT_STATUS_NOT_COMMITTED", /* 0x002d */ + "NT_STATUS_INVALID_PORT_ATTRIBUTES", /* 0x002e */ + "NT_STATUS_PORT_MESSAGE_TOO_LONG", /* 0x002f */ + "NT_STATUS_INVALID_PARAMETER_MIX", /* 0x0030 */ + "NT_STATUS_INVALID_QUOTA_LOWER", /* 0x0031 */ + "NT_STATUS_DISK_CORRUPT_ERROR", /* 0x0032 */ + "NT_STATUS_OBJECT_NAME_INVALID", /* 0x0033 */ + "NT_STATUS_OBJECT_NAME_NOT_FOUND", /* 0x0034 */ + "NT_STATUS_OBJECT_NAME_COLLISION", /* 0x0035 */ + "NT_STATUS_HANDLE_NOT_WAITABLE", /* 0x0036 */ + "NT_STATUS_PORT_DISCONNECTED", /* 0x0037 */ + "NT_STATUS_DEVICE_ALREADY_ATTACHED", /* 0x0038 */ + "NT_STATUS_OBJECT_PATH_INVALID", /* 0x0039 */ + "NT_STATUS_OBJECT_PATH_NOT_FOUND", /* 0x003a */ + "NT_STATUS_OBJECT_PATH_SYNTAX_BAD", /* 0x003b */ + "NT_STATUS_DATA_OVERRUN", /* 0x003c */ + "NT_STATUS_DATA_LATE_ERROR", /* 0x003d */ + "NT_STATUS_DATA_ERROR", /* 0x003e */ + "NT_STATUS_CRC_ERROR", /* 0x003f */ + "NT_STATUS_SECTION_TOO_BIG", /* 0x0040 */ + "NT_STATUS_PORT_CONNECTION_REFUSED", /* 0x0041 */ + "NT_STATUS_INVALID_PORT_HANDLE", /* 0x0042 */ + "NT_STATUS_SHARING_VIOLATION", /* 0x0043 */ + "NT_STATUS_QUOTA_EXCEEDED", /* 0x0044 */ + "NT_STATUS_INVALID_PAGE_PROTECTION", /* 0x0045 */ + "NT_STATUS_MUTANT_NOT_OWNED", /* 0x0046 */ + "NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", /* 0x0047 */ + "NT_STATUS_PORT_ALREADY_SET", /* 0x0048 */ + "NT_STATUS_SECTION_NOT_IMAGE", /* 0x0049 */ + "NT_STATUS_SUSPEND_COUNT_EXCEEDED", /* 0x004a */ + "NT_STATUS_THREAD_IS_TERMINATING", /* 0x004b */ + "NT_STATUS_BAD_WORKING_SET_LIMIT", /* 0x004c */ + "NT_STATUS_INCOMPATIBLE_FILE_MAP", /* 0x004d */ + "NT_STATUS_SECTION_PROTECTION", /* 0x004e */ + "NT_STATUS_EAS_NOT_SUPPORTED", /* 0x004f */ + "NT_STATUS_EA_TOO_LARGE", /* 0x0050 */ + "NT_STATUS_NONEXISTENT_EA_ENTRY", /* 0x0051 */ + "NT_STATUS_NO_EAS_ON_FILE", /* 0x0052 */ + "NT_STATUS_EA_CORRUPT_ERROR", /* 0x0053 */ + "NT_STATUS_FILE_LOCK_CONFLICT", /* 0x0054 */ + "NT_STATUS_LOCK_NOT_GRANTED", /* 0x0055 */ + "NT_STATUS_DELETE_PENDING", /* 0x0056 */ + "NT_STATUS_CTL_FILE_NOT_SUPPORTED", /* 0x0057 */ + "NT_STATUS_UNKNOWN_REVISION", /* 0x0058 */ + "NT_STATUS_REVISION_MISMATCH", /* 0x0059 */ + "NT_STATUS_INVALID_OWNER", /* 0x005a */ + "NT_STATUS_INVALID_PRIMARY_GROUP", /* 0x005b */ + "NT_STATUS_NO_IMPERSONATION_TOKEN", /* 0x005c */ + "NT_STATUS_CANT_DISABLE_MANDATORY", /* 0x005d */ + "NT_STATUS_NO_LOGON_SERVERS", /* 0x005e */ + "NT_STATUS_NO_SUCH_LOGON_SESSION", /* 0x005f */ + "NT_STATUS_NO_SUCH_PRIVILEGE", /* 0x0060 */ + "NT_STATUS_PRIVILEGE_NOT_HELD", /* 0x0061 */ + "NT_STATUS_INVALID_ACCOUNT_NAME", /* 0x0062 */ + "NT_STATUS_USER_EXISTS", /* 0x0063 */ + "NT_STATUS_NO_SUCH_USER", /* 0x0064 */ + "NT_STATUS_GROUP_EXISTS", /* 0x0065 */ + "NT_STATUS_NO_SUCH_GROUP", /* 0x0066 */ + "NT_STATUS_MEMBER_IN_GROUP", /* 0x0067 */ + "NT_STATUS_MEMBER_NOT_IN_GROUP", /* 0x0068 */ + "NT_STATUS_LAST_ADMIN", /* 0x0069 */ + "NT_STATUS_WRONG_PASSWORD", /* 0x006a */ + "NT_STATUS_ILL_FORMED_PASSWORD", /* 0x006b */ + "NT_STATUS_PASSWORD_RESTRICTION", /* 0x006c */ + "NT_STATUS_LOGON_FAILURE", /* 0x006d */ + "NT_STATUS_ACCOUNT_RESTRICTION", /* 0x006e */ + "NT_STATUS_INVALID_LOGON_HOURS", /* 0x006f */ + "NT_STATUS_INVALID_WORKSTATION", /* 0x0070 */ + "NT_STATUS_PASSWORD_EXPIRED", /* 0x0071 */ + "NT_STATUS_ACCOUNT_DISABLED", /* 0x0072 */ + "NT_STATUS_NONE_MAPPED", /* 0x0073 */ + "NT_STATUS_TOO_MANY_LUIDS_REQUESTED", /* 0x0074 */ + "NT_STATUS_LUIDS_EXHAUSTED", /* 0x0075 */ + "NT_STATUS_INVALID_SUB_AUTHORITY", /* 0x0076 */ + "NT_STATUS_INVALID_ACL", /* 0x0077 */ + "NT_STATUS_INVALID_SID", /* 0x0078 */ + "NT_STATUS_INVALID_SECURITY_DESCR", /* 0x0079 */ + "NT_STATUS_PROCEDURE_NOT_FOUND", /* 0x007a */ + "NT_STATUS_INVALID_IMAGE_FORMAT", /* 0x007b */ + "NT_STATUS_NO_TOKEN", /* 0x007c */ + "NT_STATUS_BAD_INHERITANCE_ACL", /* 0x007d */ + "NT_STATUS_RANGE_NOT_LOCKED", /* 0x007e */ + "NT_STATUS_DISK_FULL", /* 0x007f */ + "NT_STATUS_SERVER_DISABLED", /* 0x0080 */ + "NT_STATUS_SERVER_NOT_DISABLED", /* 0x0081 */ + "NT_STATUS_TOO_MANY_GUIDS_REQUESTED", /* 0x0082 */ + "NT_STATUS_GUIDS_EXHAUSTED", /* 0x0083 */ + "NT_STATUS_INVALID_ID_AUTHORITY", /* 0x0084 */ + "NT_STATUS_AGENTS_EXHAUSTED", /* 0x0085 */ + "NT_STATUS_INVALID_VOLUME_LABEL", /* 0x0086 */ + "NT_STATUS_SECTION_NOT_EXTENDED", /* 0x0087 */ + "NT_STATUS_NOT_MAPPED_DATA", /* 0x0088 */ + "NT_STATUS_RESOURCE_DATA_NOT_FOUND", /* 0x0089 */ + "NT_STATUS_RESOURCE_TYPE_NOT_FOUND", /* 0x008a */ + "NT_STATUS_RESOURCE_NAME_NOT_FOUND", /* 0x008b */ + "NT_STATUS_ARRAY_BOUNDS_EXCEEDED", /* 0x008c */ + "NT_STATUS_FLOAT_DENORMAL_OPERAND", /* 0x008d */ + "NT_STATUS_FLOAT_DIVIDE_BY_ZERO", /* 0x008e */ + "NT_STATUS_FLOAT_INEXACT_RESULT", /* 0x008f */ + "NT_STATUS_FLOAT_INVALID_OPERATION", /* 0x0090 */ + "NT_STATUS_FLOAT_OVERFLOW", /* 0x0091 */ + "NT_STATUS_FLOAT_STACK_CHECK", /* 0x0092 */ + "NT_STATUS_FLOAT_UNDERFLOW", /* 0x0093 */ + "NT_STATUS_INTEGER_DIVIDE_BY_ZERO", /* 0x0094 */ + "NT_STATUS_INTEGER_OVERFLOW", /* 0x0095 */ + "NT_STATUS_PRIVILEGED_INSTRUCTION", /* 0x0096 */ + "NT_STATUS_TOO_MANY_PAGING_FILES", /* 0x0097 */ + "NT_STATUS_FILE_INVALID", /* 0x0098 */ + "NT_STATUS_ALLOTTED_SPACE_EXCEEDED", /* 0x0099 */ + "NT_STATUS_INSUFFICIENT_RESOURCES", /* 0x009a */ + "NT_STATUS_DFS_EXIT_PATH_FOUND", /* 0x009b */ + "NT_STATUS_DEVICE_DATA_ERROR", /* 0x009c */ + "NT_STATUS_DEVICE_NOT_CONNECTED", /* 0x009d */ + "NT_STATUS_DEVICE_POWER_FAILURE", /* 0x009e */ + "NT_STATUS_FREE_VM_NOT_AT_BASE", /* 0x009f */ + "NT_STATUS_MEMORY_NOT_ALLOCATED", /* 0x00a0 */ + "NT_STATUS_WORKING_SET_QUOTA", /* 0x00a1 */ + "NT_STATUS_MEDIA_WRITE_PROTECTED", /* 0x00a2 */ + "NT_STATUS_DEVICE_NOT_READY", /* 0x00a3 */ + "NT_STATUS_INVALID_GROUP_ATTRIBUTES", /* 0x00a4 */ + "NT_STATUS_BAD_IMPERSONATION_LEVEL", /* 0x00a5 */ + "NT_STATUS_CANT_OPEN_ANONYMOUS", /* 0x00a6 */ + "NT_STATUS_BAD_VALIDATION_CLASS", /* 0x00a7 */ + "NT_STATUS_BAD_TOKEN_TYPE", /* 0x00a8 */ + "NT_STATUS_BAD_MASTER_BOOT_RECORD", /* 0x00a9 */ + "NT_STATUS_INSTRUCTION_MISALIGNMENT", /* 0x00aa */ + "NT_STATUS_INSTANCE_NOT_AVAILABLE", /* 0x00ab */ + "NT_STATUS_PIPE_NOT_AVAILABLE", /* 0x00ac */ + "NT_STATUS_INVALID_PIPE_STATE", /* 0x00ad */ + "NT_STATUS_PIPE_BUSY", /* 0x00ae */ + "NT_STATUS_ILLEGAL_FUNCTION", /* 0x00af */ + "NT_STATUS_PIPE_DISCONNECTED", /* 0x00b0 */ + "NT_STATUS_PIPE_CLOSING", /* 0x00b1 */ + "NT_STATUS_PIPE_CONNECTED", /* 0x00b2 */ + "NT_STATUS_PIPE_LISTENING", /* 0x00b3 */ + "NT_STATUS_INVALID_READ_MODE", /* 0x00b4 */ + "NT_STATUS_IO_TIMEOUT", /* 0x00b5 */ + "NT_STATUS_FILE_FORCED_CLOSED", /* 0x00b6 */ + "NT_STATUS_PROFILING_NOT_STARTED", /* 0x00b7 */ + "NT_STATUS_PROFILING_NOT_STOPPED", /* 0x00b8 */ + "NT_STATUS_COULD_NOT_INTERPRET", /* 0x00b9 */ + "NT_STATUS_FILE_IS_A_DIRECTORY", /* 0x00ba */ + "NT_STATUS_NOT_SUPPORTED", /* 0x00bb */ + "NT_STATUS_REMOTE_NOT_LISTENING", /* 0x00bc */ + "NT_STATUS_DUPLICATE_NAME", /* 0x00bd */ + "NT_STATUS_BAD_NETWORK_PATH", /* 0x00be */ + "NT_STATUS_NETWORK_BUSY", /* 0x00bf */ + "NT_STATUS_DEVICE_DOES_NOT_EXIST", /* 0x00c0 */ + "NT_STATUS_TOO_MANY_COMMANDS", /* 0x00c1 */ + "NT_STATUS_ADAPTER_HARDWARE_ERROR", /* 0x00c2 */ + "NT_STATUS_INVALID_NETWORK_RESPONSE", /* 0x00c3 */ + "NT_STATUS_UNEXPECTED_NETWORK_ERROR", /* 0x00c4 */ + "NT_STATUS_BAD_REMOTE_ADAPTER", /* 0x00c5 */ + "NT_STATUS_PRINT_QUEUE_FULL", /* 0x00c6 */ + "NT_STATUS_NO_SPOOL_SPACE", /* 0x00c7 */ + "NT_STATUS_PRINT_CANCELLED", /* 0x00c8 */ + "NT_STATUS_NETWORK_NAME_DELETED", /* 0x00c9 */ + "NT_STATUS_NETWORK_ACCESS_DENIED", /* 0x00ca */ + "NT_STATUS_BAD_DEVICE_TYPE", /* 0x00cb */ + "NT_STATUS_BAD_NETWORK_NAME", /* 0x00cc */ + "NT_STATUS_TOO_MANY_NAMES", /* 0x00cd */ + "NT_STATUS_TOO_MANY_SESSIONS", /* 0x00ce */ + "NT_STATUS_SHARING_PAUSED", /* 0x00cf */ + "NT_STATUS_REQUEST_NOT_ACCEPTED", /* 0x00d0 */ + "NT_STATUS_REDIRECTOR_PAUSED", /* 0x00d1 */ + "NT_STATUS_NET_WRITE_FAULT", /* 0x00d2 */ + "NT_STATUS_PROFILING_AT_LIMIT", /* 0x00d3 */ + "NT_STATUS_NOT_SAME_DEVICE", /* 0x00d4 */ + "NT_STATUS_FILE_RENAMED", /* 0x00d5 */ + "NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", /* 0x00d6 */ + "NT_STATUS_NO_SECURITY_ON_OBJECT", /* 0x00d7 */ + "NT_STATUS_CANT_WAIT", /* 0x00d8 */ + "NT_STATUS_PIPE_EMPTY", /* 0x00d9 */ + "NT_STATUS_CANT_ACCESS_DOMAIN_INFO", /* 0x00da */ + "NT_STATUS_CANT_TERMINATE_SELF", /* 0x00db */ + "NT_STATUS_INVALID_SERVER_STATE", /* 0x00dc */ + "NT_STATUS_INVALID_DOMAIN_STATE", /* 0x00dd */ + "NT_STATUS_INVALID_DOMAIN_ROLE", /* 0x00de */ + "NT_STATUS_NO_SUCH_DOMAIN", /* 0x00df */ + "NT_STATUS_DOMAIN_EXISTS", /* 0x00e0 */ + "NT_STATUS_DOMAIN_LIMIT_EXCEEDED", /* 0x00e1 */ + "NT_STATUS_OPLOCK_NOT_GRANTED", /* 0x00e2 */ + "NT_STATUS_INVALID_OPLOCK_PROTOCOL", /* 0x00e3 */ + "NT_STATUS_INTERNAL_DB_CORRUPTION", /* 0x00e4 */ + "NT_STATUS_INTERNAL_ERROR", /* 0x00e5 */ + "NT_STATUS_GENERIC_NOT_MAPPED", /* 0x00e6 */ + "NT_STATUS_BAD_DESCRIPTOR_FORMAT", /* 0x00e7 */ + "NT_STATUS_INVALID_USER_BUFFER", /* 0x00e8 */ + "NT_STATUS_UNEXPECTED_IO_ERROR", /* 0x00e9 */ + "NT_STATUS_UNEXPECTED_MM_CREATE_ERR", /* 0x00ea */ + "NT_STATUS_UNEXPECTED_MM_MAP_ERROR", /* 0x00eb */ + "NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", /* 0x00ec */ + "NT_STATUS_NOT_LOGON_PROCESS", /* 0x00ed */ + "NT_STATUS_LOGON_SESSION_EXISTS", /* 0x00ee */ + "NT_STATUS_INVALID_PARAMETER_1", /* 0x00ef */ + "NT_STATUS_INVALID_PARAMETER_2", /* 0x00f0 */ + "NT_STATUS_INVALID_PARAMETER_3", /* 0x00f1 */ + "NT_STATUS_INVALID_PARAMETER_4", /* 0x00f2 */ + "NT_STATUS_INVALID_PARAMETER_5", /* 0x00f3 */ + "NT_STATUS_INVALID_PARAMETER_6", /* 0x00f4 */ + "NT_STATUS_INVALID_PARAMETER_7", /* 0x00f5 */ + "NT_STATUS_INVALID_PARAMETER_8", /* 0x00f6 */ + "NT_STATUS_INVALID_PARAMETER_9", /* 0x00f7 */ + "NT_STATUS_INVALID_PARAMETER_10", /* 0x00f8 */ + "NT_STATUS_INVALID_PARAMETER_11", /* 0x00f9 */ + "NT_STATUS_INVALID_PARAMETER_12", /* 0x00fa */ + "NT_STATUS_REDIRECTOR_NOT_STARTED", /* 0x00fb */ + "NT_STATUS_REDIRECTOR_STARTED", /* 0x00fc */ + "NT_STATUS_STACK_OVERFLOW", /* 0x00fd */ + "NT_STATUS_NO_SUCH_PACKAGE", /* 0x00fe */ + "NT_STATUS_BAD_FUNCTION_TABLE", /* 0x00ff */ + "NT_STATUS_DIRECTORY_NOT_EMPTY", /* 0x0101 */ + "NT_STATUS_FILE_CORRUPT_ERROR", /* 0x0102 */ + "NT_STATUS_NOT_A_DIRECTORY", /* 0x0103 */ + "NT_STATUS_BAD_LOGON_SESSION_STATE", /* 0x0104 */ + "NT_STATUS_LOGON_SESSION_COLLISION", /* 0x0105 */ + "NT_STATUS_NAME_TOO_LONG", /* 0x0106 */ + "NT_STATUS_FILES_OPEN", /* 0x0107 */ + "NT_STATUS_CONNECTION_IN_USE", /* 0x0108 */ + "NT_STATUS_MESSAGE_NOT_FOUND", /* 0x0109 */ + "NT_STATUS_PROCESS_IS_TERMINATING", /* 0x010a */ + "NT_STATUS_INVALID_LOGON_TYPE", /* 0x010b */ + "NT_STATUS_NO_GUID_TRANSLATION", /* 0x010c */ + "NT_STATUS_CANNOT_IMPERSONATE", /* 0x010d */ + "NT_STATUS_IMAGE_ALREADY_LOADED", /* 0x010e */ + "NT_STATUS_ABIOS_NOT_PRESENT", /* 0x010f */ + "NT_STATUS_ABIOS_LID_NOT_EXIST", /* 0x0110 */ + "NT_STATUS_ABIOS_LID_ALREADY_OWNED", /* 0x0111 */ + "NT_STATUS_ABIOS_NOT_LID_OWNER", /* 0x0112 */ + "NT_STATUS_ABIOS_INVALID_COMMAND", /* 0x0113 */ + "NT_STATUS_ABIOS_INVALID_LID", /* 0x0114 */ + "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", /* 0x0115 */ + "NT_STATUS_ABIOS_INVALID_SELECTOR", /* 0x0116 */ + "NT_STATUS_NO_LDT", /* 0x0117 */ + "NT_STATUS_INVALID_LDT_SIZE", /* 0x0118 */ + "NT_STATUS_INVALID_LDT_OFFSET", /* 0x0119 */ + "NT_STATUS_INVALID_LDT_DESCRIPTOR", /* 0x011a */ + "NT_STATUS_INVALID_IMAGE_NE_FORMAT", /* 0x011b */ + "NT_STATUS_RXACT_INVALID_STATE", /* 0x011c */ + "NT_STATUS_RXACT_COMMIT_FAILURE", /* 0x011d */ + "NT_STATUS_MAPPED_FILE_SIZE_ZERO", /* 0x011e */ + "NT_STATUS_TOO_MANY_OPENED_FILES", /* 0x011f */ + "NT_STATUS_CANCELLED", /* 0x0120 */ + "NT_STATUS_CANNOT_DELETE", /* 0x0121 */ + "NT_STATUS_INVALID_COMPUTER_NAME", /* 0x0122 */ + "NT_STATUS_FILE_DELETED", /* 0x0123 */ + "NT_STATUS_SPECIAL_ACCOUNT", /* 0x0124 */ + "NT_STATUS_SPECIAL_GROUP", /* 0x0125 */ + "NT_STATUS_SPECIAL_USER", /* 0x0126 */ + "NT_STATUS_MEMBERS_PRIMARY_GROUP", /* 0x0127 */ + "NT_STATUS_FILE_CLOSED", /* 0x0128 */ + "NT_STATUS_TOO_MANY_THREADS", /* 0x0129 */ + "NT_STATUS_THREAD_NOT_IN_PROCESS", /* 0x012a */ + "NT_STATUS_TOKEN_ALREADY_IN_USE", /* 0x012b */ + "NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", /* 0x012c */ + "NT_STATUS_COMMITMENT_LIMIT", /* 0x012d */ + "NT_STATUS_INVALID_IMAGE_LE_FORMAT", /* 0x012e */ + "NT_STATUS_INVALID_IMAGE_NOT_MZ", /* 0x012f */ + "NT_STATUS_INVALID_IMAGE_PROTECT", /* 0x0130 */ + "NT_STATUS_INVALID_IMAGE_WIN_16", /* 0x0131 */ + "NT_STATUS_LOGON_SERVER_CONFLICT", /* 0x0132 */ + "NT_STATUS_TIME_DIFFERENCE_AT_DC", /* 0x0133 */ + "NT_STATUS_SYNCHRONIZATION_REQUIRED", /* 0x0134 */ + "NT_STATUS_DLL_NOT_FOUND", /* 0x0135 */ + "NT_STATUS_OPEN_FAILED", /* 0x0136 */ + "NT_STATUS_IO_PRIVILEGE_FAILED", /* 0x0137 */ + "NT_STATUS_ORDINAL_NOT_FOUND", /* 0x0138 */ + "NT_STATUS_ENTRYPOINT_NOT_FOUND", /* 0x0139 */ + "NT_STATUS_CONTROL_C_EXIT", /* 0x013a */ + "NT_STATUS_LOCAL_DISCONNECT", /* 0x013b */ + "NT_STATUS_REMOTE_DISCONNECT", /* 0x013c */ + "NT_STATUS_REMOTE_RESOURCES", /* 0x013d */ + "NT_STATUS_LINK_FAILED", /* 0x013e */ + "NT_STATUS_LINK_TIMEOUT", /* 0x013f */ + "NT_STATUS_INVALID_CONNECTION", /* 0x0140 */ + "NT_STATUS_INVALID_ADDRESS", /* 0x0141 */ + "NT_STATUS_DLL_INIT_FAILED", /* 0x0142 */ + "NT_STATUS_MISSING_SYSTEMFILE", /* 0x0143 */ + "NT_STATUS_UNHANDLED_EXCEPTION", /* 0x0144 */ + "NT_STATUS_APP_INIT_FAILURE", /* 0x0145 */ + "NT_STATUS_PAGEFILE_CREATE_FAILED", /* 0x0146 */ + "NT_STATUS_NO_PAGEFILE", /* 0x0147 */ + "NT_STATUS_INVALID_LEVEL", /* 0x0148 */ + "NT_STATUS_WRONG_PASSWORD_CORE", /* 0x0149 */ + "NT_STATUS_ILLEGAL_FLOAT_CONTEXT", /* 0x014a */ + "NT_STATUS_PIPE_BROKEN", /* 0x014b */ + "NT_STATUS_REGISTRY_CORRUPT", /* 0x014c */ + "NT_STATUS_REGISTRY_IO_FAILED", /* 0x014d */ + "NT_STATUS_NO_EVENT_PAIR", /* 0x014e */ + "NT_STATUS_UNRECOGNIZED_VOLUME", /* 0x014f */ + "NT_STATUS_SERIAL_NO_DEVICE_INITED", /* 0x0150 */ + "NT_STATUS_NO_SUCH_ALIAS", /* 0x0151 */ + "NT_STATUS_MEMBER_NOT_IN_ALIAS", /* 0x0152 */ + "NT_STATUS_MEMBER_IN_ALIAS", /* 0x0153 */ + "NT_STATUS_ALIAS_EXISTS", /* 0x0154 */ + "NT_STATUS_LOGON_NOT_GRANTED", /* 0x0155 */ + "NT_STATUS_TOO_MANY_SECRETS", /* 0x0156 */ + "NT_STATUS_SECRET_TOO_LONG", /* 0x0157 */ + "NT_STATUS_INTERNAL_DB_ERROR", /* 0x0158 */ + "NT_STATUS_FULLSCREEN_MODE", /* 0x0159 */ + "NT_STATUS_TOO_MANY_CONTEXT_IDS", /* 0x015a */ + "NT_STATUS_LOGON_TYPE_NOT_GRANTED", /* 0x015b */ + "NT_STATUS_NOT_REGISTRY_FILE", /* 0x015c */ + "NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", /* 0x015d */ + "NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", /* 0x015e */ + "NT_STATUS_FT_MISSING_MEMBER", /* 0x015f */ + "NT_STATUS_ILL_FORMED_SERVICE_ENTRY", /* 0x0160 */ + "NT_STATUS_ILLEGAL_CHARACTER", /* 0x0161 */ + "NT_STATUS_UNMAPPABLE_CHARACTER", /* 0x0162 */ + "NT_STATUS_UNDEFINED_CHARACTER", /* 0x0163 */ + "NT_STATUS_FLOPPY_VOLUME", /* 0x0164 */ + "NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", /* 0x0165 */ + "NT_STATUS_FLOPPY_WRONG_CYLINDER", /* 0x0166 */ + "NT_STATUS_FLOPPY_UNKNOWN_ERROR", /* 0x0167 */ + "NT_STATUS_FLOPPY_BAD_REGISTERS", /* 0x0168 */ + "NT_STATUS_DISK_RECALIBRATE_FAILED", /* 0x0169 */ + "NT_STATUS_DISK_OPERATION_FAILED", /* 0x016a */ + "NT_STATUS_DISK_RESET_FAILED", /* 0x016b */ + "NT_STATUS_SHARED_IRQ_BUSY", /* 0x016c */ + "NT_STATUS_FT_ORPHANING", /* 0x016d */ + "NT_STATUS_PARTITION_FAILURE", /* 0x0172 */ + "NT_STATUS_INVALID_BLOCK_LENGTH", /* 0x0173 */ + "NT_STATUS_DEVICE_NOT_PARTITIONED", /* 0x0174 */ + "NT_STATUS_UNABLE_TO_LOCK_MEDIA", /* 0x0175 */ + "NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", /* 0x0176 */ + "NT_STATUS_EOM_OVERFLOW", /* 0x0177 */ + "NT_STATUS_NO_MEDIA", /* 0x0178 */ + "NT_STATUS_NO_SUCH_MEMBER", /* 0x017a */ + "NT_STATUS_INVALID_MEMBER", /* 0x017b */ + "NT_STATUS_KEY_DELETED", /* 0x017c */ + "NT_STATUS_NO_LOG_SPACE", /* 0x017d */ + "NT_STATUS_TOO_MANY_SIDS", /* 0x017e */ + "NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", /* 0x017f */ + "NT_STATUS_KEY_HAS_CHILDREN", /* 0x0180 */ + "NT_STATUS_CHILD_MUST_BE_VOLATILE", /* 0x0181 */ + "NT_STATUS_DEVICE_CONFIGURATION_ERROR", /* 0x0182 */ + "NT_STATUS_DRIVER_INTERNAL_ERROR", /* 0x0183 */ + "NT_STATUS_INVALID_DEVICE_STATE", /* 0x0184 */ + "NT_STATUS_IO_DEVICE_ERROR", /* 0x0185 */ + "NT_STATUS_DEVICE_PROTOCOL_ERROR", /* 0x0186 */ + "NT_STATUS_BACKUP_CONTROLLER", /* 0x0187 */ + "NT_STATUS_LOG_FILE_FULL", /* 0x0188 */ + "NT_STATUS_TOO_LATE", /* 0x0189 */ + "NT_STATUS_NO_TRUST_LSA_SECRET", /* 0x018a */ + "NT_STATUS_NO_TRUST_SAM_ACCOUNT", /* 0x018b */ + "NT_STATUS_TRUSTED_DOMAIN_FAILURE", /* 0x018c */ + "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", /* 0x018d */ + "NT_STATUS_EVENTLOG_FILE_CORRUPT", /* 0x018e */ + "NT_STATUS_EVENTLOG_CANT_START", /* 0x018f */ + "NT_STATUS_TRUST_FAILURE", /* 0x0190 */ + "NT_STATUS_MUTANT_LIMIT_EXCEEDED", /* 0x0191 */ + "NT_STATUS_NETLOGON_NOT_STARTED", /* 0x0192 */ + "NT_STATUS_ACCOUNT_EXPIRED", /* 0x0193 */ + "NT_STATUS_POSSIBLE_DEADLOCK", /* 0x0194 */ + "NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", /* 0x0195 */ + "NT_STATUS_REMOTE_SESSION_LIMIT", /* 0x0196 */ + "NT_STATUS_EVENTLOG_FILE_CHANGED", /* 0x0197 */ + "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", /* 0x0198 */ + "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", /* 0x0199 */ + "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", /* 0x019a */ + "NT_STATUS_DOMAIN_TRUST_INCONSISTENT", /* 0x019b */ + "NT_STATUS_FS_DRIVER_REQUIRED", /* 0x019c */ + "NT_STATUS_NO_USER_SESSION_KEY", /* 0x0202 */ + "NT_STATUS_USER_SESSION_DELETED", /* 0x0203 */ + "NT_STATUS_RESOURCE_LANG_NOT_FOUND", /* 0x0204 */ + "NT_STATUS_INSUFF_SERVER_RESOURCES", /* 0x0205 */ + "NT_STATUS_INVALID_BUFFER_SIZE", /* 0x0206 */ + "NT_STATUS_INVALID_ADDRESS_COMPONENT", /* 0x0207 */ + "NT_STATUS_INVALID_ADDRESS_WILDCARD", /* 0x0208 */ + "NT_STATUS_TOO_MANY_ADDRESSES", /* 0x0209 */ + "NT_STATUS_ADDRESS_ALREADY_EXISTS", /* 0x020a */ + "NT_STATUS_ADDRESS_CLOSED", /* 0x020b */ + "NT_STATUS_CONNECTION_DISCONNECTED", /* 0x020c */ + "NT_STATUS_CONNECTION_RESET", /* 0x020d */ + "NT_STATUS_TOO_MANY_NODES", /* 0x020e */ + "NT_STATUS_TRANSACTION_ABORTED", /* 0x020f */ + "NT_STATUS_TRANSACTION_TIMED_OUT", /* 0x0210 */ + "NT_STATUS_TRANSACTION_NO_RELEASE", /* 0x0211 */ + "NT_STATUS_TRANSACTION_NO_MATCH", /* 0x0212 */ + "NT_STATUS_TRANSACTION_RESPONDED", /* 0x0213 */ + "NT_STATUS_TRANSACTION_INVALID_ID", /* 0x0214 */ + "NT_STATUS_TRANSACTION_INVALID_TYPE", /* 0x0215 */ + "NT_STATUS_NOT_SERVER_SESSION", /* 0x0216 */ + "NT_STATUS_NOT_CLIENT_SESSION", /* 0x0217 */ + "NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", /* 0x0218 */ + "NT_STATUS_DEBUG_ATTACH_FAILED", /* 0x0219 */ + "NT_STATUS_SYSTEM_PROCESS_TERMINATED", /* 0x021a */ + "NT_STATUS_DATA_NOT_ACCEPTED", /* 0x021b */ + "NT_STATUS_NO_BROWSER_SERVERS_FOUND", /* 0x021c */ + "NT_STATUS_VDM_HARD_ERROR", /* 0x021d */ + "NT_STATUS_DRIVER_CANCEL_TIMEOUT", /* 0x021e */ + "NT_STATUS_REPLY_MESSAGE_MISMATCH", /* 0x021f */ + "NT_STATUS_MAPPED_ALIGNMENT", /* 0x0220 */ + "NT_STATUS_IMAGE_CHECKSUM_MISMATCH", /* 0x0221 */ + "NT_STATUS_LOST_WRITEBEHIND_DATA", /* 0x0222 */ + "NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", /* 0x0223 */ + "NT_STATUS_PASSWORD_MUST_CHANGE", /* 0x0224 */ + "NT_STATUS_NOT_FOUND", /* 0x0225 */ + "NT_STATUS_NOT_TINY_STREAM", /* 0x0226 */ + "NT_STATUS_RECOVERY_FAILURE", /* 0x0227 */ + "NT_STATUS_STACK_OVERFLOW_READ", /* 0x0228 */ + "NT_STATUS_FAIL_CHECK", /* 0x0229 */ + "NT_STATUS_DUPLICATE_OBJECTID", /* 0x022a */ + "NT_STATUS_OBJECTID_EXISTS", /* 0x022b */ + "NT_STATUS_CONVERT_TO_LARGE", /* 0x022c */ + "NT_STATUS_RETRY", /* 0x022d */ + "NT_STATUS_FOUND_OUT_OF_SCOPE", /* 0x022e */ + "NT_STATUS_ALLOCATE_BUCKET", /* 0x022f */ + "NT_STATUS_PROPSET_NOT_FOUND", /* 0x0230 */ + "NT_STATUS_MARSHALL_OVERFLOW", /* 0x0231 */ + "NT_STATUS_INVALID_VARIANT", /* 0x0232 */ + "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", /* 0x0233 */ + "NT_STATUS_ACCOUNT_LOCKED_OUT", /* 0x0234 */ + "NT_STATUS_HANDLE_NOT_CLOSABLE", /* 0x0235 */ + "NT_STATUS_CONNECTION_REFUSED", /* 0x0236 */ + "NT_STATUS_GRACEFUL_DISCONNECT", /* 0x0237 */ + "NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", /* 0x0238 */ + "NT_STATUS_ADDRESS_NOT_ASSOCIATED", /* 0x0239 */ + "NT_STATUS_CONNECTION_INVALID", /* 0x023a */ + "NT_STATUS_CONNECTION_ACTIVE", /* 0x023b */ + "NT_STATUS_NETWORK_UNREACHABLE", /* 0x023c */ + "NT_STATUS_HOST_UNREACHABLE", /* 0x023d */ + "NT_STATUS_PROTOCOL_UNREACHABLE", /* 0x023e */ + "NT_STATUS_PORT_UNREACHABLE", /* 0x023f */ + "NT_STATUS_REQUEST_ABORTED", /* 0x0240 */ + "NT_STATUS_CONNECTION_ABORTED", /* 0x0241 */ + "NT_STATUS_BAD_COMPRESSION_BUFFER", /* 0x0242 */ + "NT_STATUS_USER_MAPPED_FILE", /* 0x0243 */ + "NT_STATUS_AUDIT_FAILED", /* 0x0244 */ + "NT_STATUS_TIMER_RESOLUTION_NOT_SET", /* 0x0245 */ + "NT_STATUS_CONNECTION_COUNT_LIMIT", /* 0x0246 */ + "NT_STATUS_LOGIN_TIME_RESTRICTION", /* 0x0247 */ + "NT_STATUS_LOGIN_WKSTA_RESTRICTION", /* 0x0248 */ + "NT_STATUS_IMAGE_MP_UP_MISMATCH", /* 0x0249 */ + "NT_STATUS_INSUFFICIENT_LOGON_INFO", /* 0x0250 */ + "NT_STATUS_BAD_DLL_ENTRYPOINT", /* 0x0251 */ + "NT_STATUS_BAD_SERVICE_ENTRYPOINT", /* 0x0252 */ + "NT_STATUS_LPC_REPLY_LOST", /* 0x0253 */ + "NT_STATUS_IP_ADDRESS_CONFLICT1", /* 0x0254 */ + "NT_STATUS_IP_ADDRESS_CONFLICT2", /* 0x0255 */ + "NT_STATUS_REGISTRY_QUOTA_LIMIT", /* 0x0256 */ + "NT_STATUS_PATH_NOT_COVERED", /* 0x0257 */ + "NT_STATUS_NO_CALLBACK_ACTIVE", /* 0x0258 */ + "NT_STATUS_LICENSE_QUOTA_EXCEEDED", /* 0x0259 */ + "NT_STATUS_PWD_TOO_SHORT", /* 0x025a */ + "NT_STATUS_PWD_TOO_RECENT", /* 0x025b */ + "NT_STATUS_PWD_HISTORY_CONFLICT", /* 0x025c */ + "NT_STATUS_PLUGPLAY_NO_DEVICE", /* 0x025e */ + "NT_STATUS_UNSUPPORTED_COMPRESSION", /* 0x025f */ + "NT_STATUS_INVALID_HW_PROFILE", /* 0x0260 */ + "NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", /* 0x0261 */ + "NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", /* 0x0262 */ + "NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", /* 0x0263 */ + "NT_STATUS_RESOURCE_NOT_OWNED", /* 0x0264 */ + "NT_STATUS_TOO_MANY_LINKS", /* 0x0265 */ + "NT_STATUS_QUOTA_LIST_INCONSISTENT", /* 0x0266 */ + "NT_STATUS_FILE_IS_OFFLINE" /* 0x0267 */ +}; + +#define NT_STATUS(a) nt_status_to_string[a & 0x3FFFFFFF] + +struct Packet +{ + size_t frame; + + uint8_t magic[4]; + + bool valid_smb() { + return !memcmp(smb_hdr.magic, magic, 4); + } + + Packet(const uint8_t *data, size_t size) : + ip_hdr(data + 14, size - 14), + tcp_hdr(data + 14 + ip_hdr.header_length, + size - 14 - ip_hdr.header_length), + smb_hdr(data + 14 + ip_hdr.header_length + tcp_hdr.length, + size - 14 - ip_hdr.header_length - tcp_hdr.length) + { + const uint8_t da[] = { 0xFF, 'S', 'M', 'B' }; + + memcpy(magic, da, sizeof(da)); + + if (valid_smb()) { + size_t len = 14 + ip_hdr.header_length + tcp_hdr.length + 36; + + switch (smb_hdr.command) { + case NtCreateAndXRequest::COMMAND: + if (smb_hdr.flags & 0x80) { + ntcreate_resp = NtCreateAndXResponse(data+len, size - len); + } else { + ntcreate_req = NtCreateAndXRequest(data + len, size - len); + } + break; + case ReadAndXRequest::COMMAND: + if (!(smb_hdr.flags & 0x80)) { + read_req = ReadAndXRequest(data + len, size - len); + } + break; + case WriteAndXRequest::COMMAND: + if (!(smb_hdr.flags & 0x80)) { + write_req = WriteAndXRequest(data + len, size - len); + } + break; + case CloseRequest::COMMAND: + if (!(smb_hdr.flags & 0x80)) { + close_req = CloseRequest(data + len, size - len); + } + break; + } + } + } + + ip ip_hdr; + tcp tcp_hdr; + smb smb_hdr; + + NtCreateAndXRequest ntcreate_req; + NtCreateAndXResponse ntcreate_resp; + ReadAndXRequest read_req; + WriteAndXRequest write_req; + CloseRequest close_req; +}; + +int main(int argc, char **argv) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + pcap_t *cap; + struct pcap_pkthdr *pkt_hdr; + const uint8_t *data; + + static struct option long_opts[] = { + { "show-files", 0, 0, 's' }, + { "drop-incomplete-sessions", 0, 0, 'i' }, + { 0, 0, 0, 0 } + }; + const char *short_opts = "si"; + int opt_ind; + char ch; + int show_files = 0; + int drop_incomplete_sessions = 0; + + while ((ch = getopt_long(argc,argv,short_opts,long_opts,&opt_ind)) != -1) { + switch (ch) { + case 's': + show_files = 1; + break; + case 'i': + drop_incomplete_sessions = 1; + break; + default: + break; + } + } + + if ((argc - optind) != 1) { + std::cout << "Usage: " << argv[0] << " [OPTIONS] FILE" << std::endl; + exit(1); + } + + cap = pcap_open_offline(argv[optind], errbuf); + + if (!cap) { + std::cout << "pcap_open_offline(" << argv[optind] << "): " << errbuf + << std::endl; + exit(1); + } + + std::vector<Packet> packets; + size_t frame = 0; + std::set<uint16_t> current_fids; + + while (1 == pcap_next_ex(cap, &pkt_hdr, &data)) { + Packet packet(data, pkt_hdr->len); + + ++frame; + + if (packet.valid_smb()) { + packet.frame = frame; + packets.push_back(packet); + } + } + + pcap_close(cap); + + for (std::vector<Packet>::iterator i = packets.begin(); + i != packets.end(); ++i) { + if (!(i->smb_hdr.flags & 0x80)) { + /* we have a request */ + std::vector<Packet>::iterator j; + + /* look ahead for the response */ + for (j = i; j != packets.end(); ++j) { + if (j->smb_hdr.flags & 0x80 && // response + j->smb_hdr.command == i->smb_hdr.command && + j->smb_hdr.tid == i->smb_hdr.tid && + j->smb_hdr.pid == i->smb_hdr.pid && + j->smb_hdr.uid == i->smb_hdr.uid && + j->smb_hdr.mid == i->smb_hdr.mid) { + break; + } + } + + /* no response? guess we can't display this command */ + if (j == packets.end()) continue; + + size_t len; + + switch (i->smb_hdr.command) { + case NtCreateAndXRequest::COMMAND: + std::cout << "NTCreateX \"" << i->ntcreate_req.file_name << "\" " + << i->ntcreate_req.create_options << " " + << i->ntcreate_req.disposition << " " + << j->ntcreate_resp.fid << " " + << NT_STATUS(j->smb_hdr.nt_status) << std::endl; + current_fids.insert(j->ntcreate_resp.fid); + break; + case ReadAndXRequest::COMMAND: + len = i->read_req.max_count_high * 64 * 1024 + + i->read_req.max_count_low; + + if (!drop_incomplete_sessions || current_fids.count(i->read_req.fid)) { + std::cout << "ReadX " << i->read_req.fid << " " + << i->read_req.offset << " " + << len << " " << len << " " + << NT_STATUS(j->smb_hdr.nt_status) << std::endl; + } + break; + case WriteAndXRequest::COMMAND: + len = i->write_req.data_length_hi * 64 * 1024 + + i->write_req.data_length_lo; + + if (!drop_incomplete_sessions||current_fids.count(i->write_req.fid)) { + std::cout << "WriteX " << i->write_req.fid << " " + << i->write_req.offset << " " + << len << " " << len << " " + << NT_STATUS(j->smb_hdr.nt_status) << std::endl; + } + break; + case CloseRequest::COMMAND: + if (!drop_incomplete_sessions||current_fids.count(i->close_req.fid)) { + std::cout << "Close " << i->close_req.fid << " " + << NT_STATUS(j->smb_hdr.nt_status) << std::endl; + } + current_fids.erase(i->close_req.fid); + break; + } + } + } + + return 0; +} diff --git a/examples/pcap2nbench/ntcreateandxrequest.cpp b/examples/pcap2nbench/ntcreateandxrequest.cpp new file mode 100644 index 0000000..5efc256 --- /dev/null +++ b/examples/pcap2nbench/ntcreateandxrequest.cpp @@ -0,0 +1,73 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> + +#include "ntcreateandxrequest.hpp" + +NtCreateAndXRequest::NtCreateAndXRequest(const uint8_t *data, size_t size) +{ + if (size < 52) { + std::cerr << "Invalid NtCreateAndX Request" << std::endl; + return; + } + + word_count = data[0]; + and_x_command = data[1]; + reserved = data[2]; + memcpy(&and_x_offset, data + 3, 2); + reserved1 = data[5]; + memcpy(&file_name_len, data + 6, 2); + memcpy(&create_flags, data + 8, 4); + memcpy(&root_fid, data + 12, 4); + memcpy(&access_mask, data + 16, 4); + memcpy(&allocation_size, data + 20, 8); + memcpy(&file_attributes, data + 28, 4); + memcpy(&share_access, data + 32, 4); + memcpy(&disposition, data + 36, 4); + memcpy(&create_options, data + 40, 4); + memcpy(&impersonation, data + 44, 4); + security_flags = data[48]; + memcpy(&byte_count, data + 49, 2); + file_name = (const char *)(data + 51); +} + +std::ostream &operator<<(std::ostream &lhs, const NtCreateAndXRequest &rhs) +{ + lhs << "Word Count: " << (uint16_t)rhs.word_count << std::endl + << "AndXCommand: " << (uint16_t)rhs.and_x_command << std::endl + << "Reserved: " << (uint16_t)rhs.reserved << std::endl + << "AndXOffset: " << rhs.and_x_offset << std::endl + << "Reserved: " << (uint16_t)rhs.reserved1 << std::endl + << "File Name Len: " << rhs.file_name_len << std::endl + << "Create Flags: " << rhs.create_flags << std::endl + << "Root FID: " << rhs.root_fid << std::endl + << "Access Mask: " << rhs.access_mask << std::endl + << "Allocation Size: " << rhs.allocation_size << std::endl + << "File Attributes: " << rhs.file_attributes << std::endl + << "Share Access: " << rhs.share_access << std::endl + << "Disposition: " << rhs.disposition << std::endl + << "Create Options: " << rhs.create_options << std::endl + << "Impersonation: " << rhs.impersonation << std::endl + << "Security Flags: " << (uint16_t)rhs.security_flags << std::endl + << "Byte Count: " << rhs.byte_count << std::endl + << "File Name: " << rhs.file_name << std::endl; + return lhs; +} diff --git a/examples/pcap2nbench/ntcreateandxrequest.hpp b/examples/pcap2nbench/ntcreateandxrequest.hpp new file mode 100644 index 0000000..07c19fd --- /dev/null +++ b/examples/pcap2nbench/ntcreateandxrequest.hpp @@ -0,0 +1,57 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef _NT_CREATE_AND_X_REQUEST_HPP +#define _NT_CREATE_AND_X_REQUEST_HPP + +#include <iostream> +#include <stdint.h> + +struct NtCreateAndXRequest { + enum { + COMMAND = 0xa2 + }; + + NtCreateAndXRequest() { } + NtCreateAndXRequest(const uint8_t *data, size_t size); + + uint8_t word_count; + uint8_t and_x_command; + uint8_t reserved; + uint16_t and_x_offset; + uint8_t reserved1; + uint16_t file_name_len; + uint32_t create_flags; + uint32_t root_fid; + uint32_t access_mask; + uint64_t allocation_size; + uint32_t file_attributes; + uint32_t share_access; + uint32_t disposition; + uint32_t create_options; + uint32_t impersonation; + uint8_t security_flags; + uint16_t byte_count; + std::string file_name; +}; + +std::ostream &operator<<(std::ostream &lhs, const NtCreateAndXRequest &rhs); + +#endif diff --git a/examples/pcap2nbench/ntcreateandxresponse.cpp b/examples/pcap2nbench/ntcreateandxresponse.cpp new file mode 100644 index 0000000..7e427b9 --- /dev/null +++ b/examples/pcap2nbench/ntcreateandxresponse.cpp @@ -0,0 +1,42 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> + +#include "ntcreateandxresponse.hpp" + +NtCreateAndXResponse::NtCreateAndXResponse(const uint8_t *data, size_t size) +{ + if (size < 71) { + return; + } + + word_count = data[0]; + and_x_command = data[1]; + reserved = data[2]; + memcpy(&and_x_offset, data + 3, 2); + oplock_level = data[5]; + memcpy(&fid, data + 6, 2); +} + +std::ostream &operator<<(std::ostream &lhs, const NtCreateAndXResponse &rhs) +{ + return lhs; +} diff --git a/examples/pcap2nbench/ntcreateandxresponse.hpp b/examples/pcap2nbench/ntcreateandxresponse.hpp new file mode 100644 index 0000000..c17ff21 --- /dev/null +++ b/examples/pcap2nbench/ntcreateandxresponse.hpp @@ -0,0 +1,57 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef _NT_CREATE_AND_X_RESPONSE_HPP +#define _NT_CREATE_AND_X_RESPONSE_HPP + +#include <iostream> +#include <stdint.h> + +struct NtCreateAndXResponse { + enum { + COMMAND = 0xa2 + }; + + NtCreateAndXResponse() {} + NtCreateAndXResponse(const uint8_t *data, size_t size); + + uint8_t word_count; + uint8_t and_x_command; + uint8_t reserved; + uint16_t and_x_offset; + uint8_t oplock_level; + uint16_t fid; + uint32_t create_action; + uint64_t create_date; + uint64_t access_date; + uint64_t write_date; + uint64_t change_date; + uint32_t file_attributes; + uint64_t allocation_size; + uint64_t end_of_file; + uint16_t file_type; + uint16_t ipc_state; + uint8_t is_directory; + uint16_t byte_count; +}; + +std::ostream &operator<<(std::ostream &lhs, const NtCreateAndXResponse &rhs); + +#endif diff --git a/examples/pcap2nbench/readandxrequest.cpp b/examples/pcap2nbench/readandxrequest.cpp new file mode 100644 index 0000000..87411fc --- /dev/null +++ b/examples/pcap2nbench/readandxrequest.cpp @@ -0,0 +1,60 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> + +#include "readandxrequest.hpp" + +ReadAndXRequest::ReadAndXRequest(const uint8_t *data, size_t size) +{ + if (size < 27) { + std::cerr << "Invalid ReadAndX Request" << std::endl; + return; + } + word_count = data[0]; + and_x_command = data[1]; + reserved = data[2]; + memcpy(&and_x_offset, data + 3, 2); + memcpy(&fid, data + 5, 2); + memcpy(&offset, data + 7, 4); + memcpy(&max_count_low, data + 11, 2); + memcpy(&min_count, data + 13, 2); + memcpy(&max_count_high, data + 15, 4); + memcpy(&remaining, data + 19, 2); + memcpy(&high_offset, data + 21, 4); + memcpy(&byte_count, data + 25, 2); +} + +std::ostream &operator<<(std::ostream &lhs, const ReadAndXRequest &rhs) +{ + lhs << "Word Count: " << (uint16_t)rhs.word_count << std::endl + << "AndXCommand: " << (uint16_t)rhs.and_x_command << std::endl + << "Reserved: " << (uint16_t)rhs.reserved << std::endl + << "AndX Offset: " << rhs.and_x_offset << std::endl + << "Fid: " << rhs.fid << std::endl + << "Offset: " << rhs.offset << std::endl + << "Max Count Low: " << rhs.max_count_low << std::endl + << "Min Count: " << rhs.min_count << std::endl + << "Max Count High: " << rhs.max_count_high << std::endl + << "Remaining: " << rhs.remaining << std::endl + << "High Offset: " << rhs.high_offset << std::endl + << "Byte Count: " << rhs.byte_count << std::endl; + return lhs; +} diff --git a/examples/pcap2nbench/readandxrequest.hpp b/examples/pcap2nbench/readandxrequest.hpp new file mode 100644 index 0000000..21e0bca --- /dev/null +++ b/examples/pcap2nbench/readandxrequest.hpp @@ -0,0 +1,51 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef _READ_AND_X_REQUEST_HPP +#define _READ_AND_X_REQUEST_HPP + +#include <iostream> +#include <stdint.h> + +struct ReadAndXRequest { + enum { + COMMAND = 0x2e + }; + + ReadAndXRequest() {} + ReadAndXRequest(const uint8_t *data, size_t size); + + uint8_t word_count; + uint8_t and_x_command; + uint8_t reserved; + uint16_t and_x_offset; + uint16_t fid; + uint32_t offset; + uint16_t max_count_low; + uint16_t min_count; + uint32_t max_count_high; + uint16_t remaining; + uint32_t high_offset; + uint16_t byte_count; +}; + +std::ostream &operator<<(std::ostream &lhs, const ReadAndXRequest &rhs); + +#endif diff --git a/examples/pcap2nbench/readandxresponse.hpp b/examples/pcap2nbench/readandxresponse.hpp new file mode 100644 index 0000000..8ecb3a3 --- /dev/null +++ b/examples/pcap2nbench/readandxresponse.hpp @@ -0,0 +1,47 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef _READ_AND_X_RESPONSE_HPP +#define _READ_AND_X_RESPONSE_HPP + +class ReadAndXResponse { + ReadAndXResponse(const uint8_t *data, size_t size); + + uint8_t word_count; + uint8_t and_x_command; + uint8_t reserved; + uint16_t and_x_offset; + uint8_t oplock_level; + uint16_t fid; + uint32_t create_action; + uint64_t created_date; + uint64_t access_date; + uint64_t write_date; + uint64_t change_date; + uint32_t file_attributes; + uint64_t allocation_size; + uint64_t end_of_file; + uint16_t file_type; + uint16_t ipc_state; + uint8_t is_directory; + uint16_t byte_count; +}; + +#endif diff --git a/examples/pcap2nbench/smb.cpp b/examples/pcap2nbench/smb.cpp new file mode 100644 index 0000000..78f8aaf --- /dev/null +++ b/examples/pcap2nbench/smb.cpp @@ -0,0 +1,71 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> + +#include "smb.hpp" + +smb::smb(const uint8_t *data, size_t length) +{ + if (length < 36) { + memset(magic, 0, 4); + return; + } + + /* This code assumes Little Endian... Don't say I didn't warn you */ + memcpy(&size, data + 2, 2); + memcpy(magic, data + 4, 4); + + command = data[8]; + + memcpy(&nt_status, data + 9, 4); + + flags = data[13]; + + memcpy(&flags2, data + 14, 2); + memcpy(&pid_hi, data + 16, 2); + memcpy(signature, data + 18, 8); + memcpy(&reserved, data + 26, 2); + memcpy(&tid, data + 28, 2); + memcpy(&pid, data + 30, 2); + memcpy(&uid, data + 32, 2); + memcpy(&mid, data + 34, 2); +} + +std::ostream &operator<<(std::ostream &lhs, const smb &rhs) +{ + lhs << "Magic: "; + for (int i = 1; i < 4; i++) { + lhs << rhs.magic[i]; + } + lhs << std::endl; + + lhs << "Command: " << (uint16_t)rhs.command << std::endl + << "NT Status: " << rhs.nt_status << std::endl + << "Flags: " << (uint16_t)rhs.flags << std::endl + << "Flags2: " << rhs.flags2 << std::endl + << "Pid Hi: " << rhs.pid_hi << std::endl + << "Tid: " << rhs.tid << std::endl + << "Pid: " << rhs.pid << std::endl + << "Uid: " << rhs.uid << std::endl + << "Mid: " << rhs.mid << std::endl; + + return lhs; +} diff --git a/examples/pcap2nbench/smb.hpp b/examples/pcap2nbench/smb.hpp new file mode 100644 index 0000000..79a7f8c --- /dev/null +++ b/examples/pcap2nbench/smb.hpp @@ -0,0 +1,48 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef _SMB_HPP +#define _SMB_HPP + +#include <iostream> +#include <stdint.h> + +struct smb { + smb(const uint8_t *data, size_t length); + + uint16_t size; + + uint8_t magic[4]; /* 0xff, 'S', 'M', 'B' */ + uint8_t command; + uint32_t nt_status; + uint8_t flags; + uint16_t flags2; + uint16_t pid_hi; + uint8_t signature[8]; + uint16_t reserved; + uint16_t tid; + uint16_t pid; + uint16_t uid; + uint16_t mid; +}; + +std::ostream &operator<<(std::ostream &lhs, const smb &rhs); + +#endif diff --git a/examples/pcap2nbench/tcp.cpp b/examples/pcap2nbench/tcp.cpp new file mode 100644 index 0000000..8b51060 --- /dev/null +++ b/examples/pcap2nbench/tcp.cpp @@ -0,0 +1,59 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> + +#include "tcp.hpp" + +tcp::tcp(const uint8_t *data, size_t size) +{ + if (size < 18) { + std::cerr << "Invalid TCP header" << std::endl; + } + + memcpy(&src_port, data, 2); + src_port = ntohs(src_port); + memcpy(&dst_port, data + 2, 2); + dst_port = ntohs(dst_port); + memcpy(&seq_number, data + 4, 4); + seq_number = ntohl(seq_number); + memcpy(&ack_number, data + 8, 4); + ack_number = ntohl(ack_number); + length = ((data[12] & 0xF0) >> 4) * 4; + flags = ((data[12] & 0x0F) << 8) | data[13]; + memcpy(&window_size, data + 14, 2); + window_size = ntohs(window_size); + memcpy(&checksum, data + 16, 2); + checksum = ntohs(checksum); +} + +std::ostream &operator<<(std::ostream &lhs, const tcp &rhs) +{ + lhs << "Source Port: " << rhs.src_port << std::endl + << "Destination Port: " << rhs.dst_port << std::endl + << "Sequence Number: " << rhs.seq_number << std::endl + << "Ack Number: " << rhs.ack_number << std::endl + << "Length: " << (uint16_t)(rhs.length) << std::endl + << "Flags: " << rhs.flags << std::endl + << "Window Size: " << rhs.window_size << std::endl + << "Checksum: " << rhs.checksum << std::endl; + + return lhs; +} diff --git a/examples/pcap2nbench/tcp.hpp b/examples/pcap2nbench/tcp.hpp new file mode 100644 index 0000000..5eb7aaa --- /dev/null +++ b/examples/pcap2nbench/tcp.hpp @@ -0,0 +1,42 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef _TCP_HPP +#define _TCP_HPP + +#include <iostream> +#include <stdint.h> + +struct tcp { + tcp(const uint8_t *data, size_t length); + + uint16_t src_port; + uint16_t dst_port; + uint32_t seq_number; + uint32_t ack_number; + uint8_t length; + uint16_t flags; + uint16_t window_size; + uint16_t checksum; +}; + +std::ostream &operator<<(std::ostream &lhs, const tcp &rhs); + +#endif diff --git a/examples/pcap2nbench/writeandxrequest.cpp b/examples/pcap2nbench/writeandxrequest.cpp new file mode 100644 index 0000000..f56a031 --- /dev/null +++ b/examples/pcap2nbench/writeandxrequest.cpp @@ -0,0 +1,65 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#include <netinet/in.h> + +#include "writeandxrequest.hpp" + +WriteAndXRequest::WriteAndXRequest(const uint8_t *data, size_t size) +{ + if (size < 31) { + std::cerr << "Invalid WriteAndX Request" << std::endl; + return; + } + word_count = data[0]; + and_x_command = data[1]; + reserved = data[2]; + memcpy(&and_x_offset, data + 3, 2); + memcpy(&fid, data + 5, 2); + memcpy(&offset, data + 7, 4); + memcpy(&reserved1, data + 11, 4); + memcpy(&write_mode, data + 15, 2); + memcpy(&remaining, data + 17, 2); + memcpy(&data_length_hi, data + 19, 2); + memcpy(&data_length_lo, data + 21, 2); + memcpy(&data_offset, data + 23, 2); + memcpy(&high_offset, data + 25, 4); + memcpy(&byte_count, data + 29, 2); + +} + +std::ostream &operator<<(std::ostream &lhs, const WriteAndXRequest &rhs) +{ + lhs << "Word Count: " << (uint16_t)rhs.word_count << std::endl + << "AndXCommand: " << (uint16_t)rhs.and_x_command << std::endl + << "Reserved: " << (uint16_t)rhs.reserved << std::endl + << "AndX Offset: " << rhs.and_x_offset << std::endl + << "Fid: " << rhs.fid << std::endl + << "Offset: " << rhs.offset << std::endl + << "Reserved: " << rhs.reserved1 << std::endl + << "Write Mode: " << rhs.write_mode << std::endl + << "Remaining: " << rhs.remaining << std::endl + << "Data Length Hi: " << rhs.data_length_hi << std::endl + << "Data Length Lo: " << rhs.data_length_lo << std::endl + << "Data Offset: " << rhs.data_offset << std::endl + << "High Offset: " << rhs.high_offset << std::endl + << "Byte Count: " << rhs.byte_count << std::endl; + return lhs; +} diff --git a/examples/pcap2nbench/writeandxrequest.hpp b/examples/pcap2nbench/writeandxrequest.hpp new file mode 100644 index 0000000..c91bcc3 --- /dev/null +++ b/examples/pcap2nbench/writeandxrequest.hpp @@ -0,0 +1,53 @@ +/*\ + * pcap2nbench - Converts libpcap network traces to nbench input + * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Written by Anthony Liguori <aliguori@us.ibm.com> +\*/ + +#ifndef _WRITE_AND_X_REQUEST_HPP +#define _WRITE_AND_X_REQUEST_HPP + +#include <iostream> +#include <stdint.h> + +struct WriteAndXRequest { + enum { + COMMAND = 0x2f + }; + + WriteAndXRequest() {} + WriteAndXRequest(const uint8_t *data, size_t size); + + uint8_t word_count; + uint8_t and_x_command; + uint8_t reserved; + uint16_t and_x_offset; + uint16_t fid; + uint32_t offset; + uint32_t reserved1; + uint16_t write_mode; + uint16_t remaining; + uint16_t data_length_hi; + uint16_t data_length_lo; + uint16_t data_offset; + uint32_t high_offset; + uint16_t byte_count; +}; + +std::ostream &operator<<(std::ostream &lhs, const WriteAndXRequest &rhs); + +#endif diff --git a/examples/pdb/Makefile b/examples/pdb/Makefile new file mode 100644 index 0000000..09d901d --- /dev/null +++ b/examples/pdb/Makefile @@ -0,0 +1,31 @@ +# Makefile for samba-pdb examples +# Variables + +CC = gcc +LIBTOOL = libtool + +SAMBA_SRC = ../../source +SAMBA_INCL = ../../source/include +UBIQX_SRC = ../../source/ubiqx +SMBWR_SRC = ../../source/smbwrapper +CFLAGS = -I$(SAMBA_SRC) -I$(SAMBA_INCL) -I$(UBIQX_SRC) -I$(SMBWR_SRC) -Wall -g -I/usr/include/heimdal -fPIC +PDB_OBJS = test.la + +# Default target + +default: $(PDB_OBJS) + +# Pattern rules + +%.la: %.lo + $(LIBTOOL) --mode=link $(CC) -module -o $@ $< $(LDFLAGS) -rpath /usr/lib/samba/pdb/ + +%.lo: %.c + $(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS) -c $< + +# Misc targets + +clean: + rm -rf .libs + rm -f core *~ *% *.bak \ + $(PDB_OBJS) $(PDB_OBJS:.la=.o) $(PDB_OBJS:.la=.lo) diff --git a/examples/pdb/README b/examples/pdb/README new file mode 100644 index 0000000..692d322 --- /dev/null +++ b/examples/pdb/README @@ -0,0 +1,20 @@ +README for Samba Password Database (PDB) examples +==================================================== +Jelmer Vernooij <jelmer@nl.linux.org> +Stefan (metze) Metzmacher <metze@samba.org> + +The test.c file in this directory contains a very basic example of +a pdb plugin. It just prints the name of the function that is executed using +DEBUG. Maybe it's nice to include some of the arguments to the function in the +future too.. + +To debug passdb backends, try to run gdb on the 'pdbedit' executable. That's +really much easier than restarting smbd constantly and attaching with your +debugger. + +New passdb plugins should go into the samba lib directory, (/usr/lib/samba/pdb/ +for most distributions). An example would be: /usr/lib/samba/pdb/test.so + +Be aware that the SQL and XML based passdb modules have been removed since the +3.0.23 release. More information of external support for SQL passdb modules +can be found at http://pdbsql.sourceforge.net/. diff --git a/examples/pdb/test.c b/examples/pdb/test.c new file mode 100644 index 0000000..a5e7dac --- /dev/null +++ b/examples/pdb/test.c @@ -0,0 +1,115 @@ +/* + * Test password backend for samba + * Copyright (C) Jelmer Vernooij 2002 + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#include "includes.h" +#include "passdb.h" + +static int testsam_debug_level = DBGC_ALL; + +#undef DBGC_CLASS +#define DBGC_CLASS testsam_debug_level + +/****************************************************************** + Lookup a name in the SAM database +******************************************************************/ + +static NTSTATUS testsam_getsampwnam (struct pdb_methods *methods, struct samu *user, const char *sname) +{ + DEBUG(10, ("testsam_getsampwnam called\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +/*************************************************************************** + Search by sid + **************************************************************************/ + +static NTSTATUS testsam_getsampwsid (struct pdb_methods *methods, struct samu *user, const struct dom_sid *sid) +{ + DEBUG(10, ("testsam_getsampwsid called\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +/*************************************************************************** + Delete a struct samu +****************************************************************************/ + +static NTSTATUS testsam_delete_sam_account(struct pdb_methods *methods, struct samu *sam_pass) +{ + DEBUG(10, ("testsam_delete_sam_account called\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +/*************************************************************************** + Modifies an existing struct samu +****************************************************************************/ + +static NTSTATUS testsam_update_sam_account (struct pdb_methods *methods, struct samu *newpwd) +{ + DEBUG(10, ("testsam_update_sam_account called\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +/*************************************************************************** + Adds an existing struct samu +****************************************************************************/ + +static NTSTATUS testsam_add_sam_account (struct pdb_methods *methods, struct samu *newpwd) +{ + DEBUG(10, ("testsam_add_sam_account called\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS testsam_init(struct pdb_methods **pdb_method, const char *location) +{ + NTSTATUS nt_status; + + if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) { + return nt_status; + } + + (*pdb_method)->name = "testsam"; + + /* Functions your pdb module doesn't provide should not be + set, make_pdb_methods() already provide suitable defaults for missing functions */ + + (*pdb_method)->getsampwnam = testsam_getsampwnam; + (*pdb_method)->getsampwsid = testsam_getsampwsid; + (*pdb_method)->add_sam_account = testsam_add_sam_account; + (*pdb_method)->update_sam_account = testsam_update_sam_account; + (*pdb_method)->delete_sam_account = testsam_delete_sam_account; + + testsam_debug_level = debug_add_class("testsam"); + if (testsam_debug_level == -1) { + testsam_debug_level = DBGC_ALL; + DEBUG(0, ("testsam: Couldn't register custom debugging class!\n")); + } else DEBUG(0, ("testsam: Debug class number of 'testsam': %d\n", testsam_debug_level)); + + DEBUG(0, ("Initializing testsam\n")); + if (location) + DEBUG(10, ("Location: %s\n", location)); + + return NT_STATUS_OK; +} + +static_decl_pdb; +NTSTATUS pdb_test_init(TALLOC_CTX *ctx) +{ + return smb_register_passdb(PASSDB_INTERFACE_VERSION, "testsam", + testsam_init); +} diff --git a/examples/pdb/wscript_build b/examples/pdb/wscript_build new file mode 100644 index 0000000..11d00ba --- /dev/null +++ b/examples/pdb/wscript_build @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +bld.SAMBA3_MODULE('pdb_test', + subsystem='pdb', + source='test.c', + deps='samba-util', + init_function='', + internal_module=bld.SAMBA3_IS_STATIC_MODULE('pdb_test'), + enabled=bld.SAMBA3_IS_ENABLED_MODULE('pdb_test')) + diff --git a/examples/perfcounter/Makefile b/examples/perfcounter/Makefile new file mode 100644 index 0000000..86e2190 --- /dev/null +++ b/examples/perfcounter/Makefile @@ -0,0 +1,38 @@ +# +# Copyright (C) Marcin Krzysztof Porwit 2005 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <http://www.gnu.org/licenses/>. +# + +SAMBA_SRC_DIR=../../source3 +TDB_SRC_DIR=$(SAMBA_SRC_DIR)/../lib/tdb + +CFLAGS = -g -I$(SAMBA_SRC_DIR) -I$(SAMBA_SRC_DIR)/include -I$(TDB_SRC_DIR)/include -I../../ +CC = gcc + +PROGS = perfcount +TDB_OBJ = $(TDB_SRC_DIR)/common/tdb.o $(TDB_SRC_DIR)/common/dump.o \ + $(TDB_SRC_DIR)/common/error.o $(TDB_SRC_DIR)/common/freelist.o \ + $(TDB_SRC_DIR)/common/io.o $(TDB_SRC_DIR)/common/lock.o \ + $(TDB_SRC_DIR)/common/open.o $(TDB_SRC_DIR)/common/transaction.o \ + $(TDB_SRC_DIR)/common/traverse.o $(TDB_SRC_DIR)/common/hash.o +PERF_WRITER_OBJ = perf_writer.o perf_writer_mem.o perf_writer_util.o perf_writer_cpu.o perf_writer_process.o perf_writer_disk.o + +default: $(PROGS) + +perfcount: $(PERF_WRITER_OBJ) + $(CC) $(CFLAGS) -o perfcount $(PERF_WRITER_OBJ) $(TDB_OBJ) + +clean: + rm -f $(PROGS) *.o *~ *% core diff --git a/examples/perfcounter/perf.h b/examples/perfcounter/perf.h new file mode 100644 index 0000000..03b5448 --- /dev/null +++ b/examples/perfcounter/perf.h @@ -0,0 +1,210 @@ +/* + * Unix SMB/CIFS implementation. + * Performance Counter Daemon + * + * Copyright (C) Marcin Krzysztof Porwit 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PERF_H__ +#define __PERF_H__ + +#define _PUBLIC_ + +#ifdef HAVE_STDBOOL_H +#include <stdbool.h> +#endif + +#if !defined(HAVE_BOOL) +#ifdef HAVE__Bool +#define bool _Bool +#else +#error Need a real boolean type +#endif +#endif + + +#include <stdlib.h> +#include <time.h> +#include <math.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <signal.h> +#include <stdarg.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <limits.h> +#include <tdb.h> +#include "librpc/gen_ndr/perfcount.h" +#include <sys/statfs.h> +#include <sys/times.h> +#include <sys/sysinfo.h> + +#define NUM_COUNTERS 10 + +#define NAME_LEN 256 +#define HELP_LEN 1024 + +#define PERF_OBJECT 0 +#define PERF_INSTANCE 1 +#define PERF_COUNTER 2 + +#define FALSE 0 +#define TRUE !FALSE + +#define PROC_BUF 256 +#define LARGE_BUF 16384 + +typedef struct perf_counter +{ + int index; + char name[NAME_LEN]; + char help[HELP_LEN]; + char relationships[NAME_LEN]; + unsigned int counter_type; + int record_type; +} PerfCounter; + +typedef struct mem_data +{ + unsigned int availPhysKb; + unsigned int availSwapKb; + unsigned int totalPhysKb; + unsigned int totalSwapKb; +} MemData; + +typedef struct mem_info +{ + PerfCounter memObjDesc; + PerfCounter availPhysKb; + PerfCounter availSwapKb; + PerfCounter totalPhysKb; + PerfCounter totalSwapKb; + MemData *data; +} MemInfo; + +typedef struct cpu_data +{ + unsigned long long user; + unsigned long long nice; + unsigned long long system; + unsigned long long idle; +} CPUData; + +typedef struct cpu_info +{ + unsigned int numCPUs; + PerfCounter cpuObjDesc; + PerfCounter userCPU; + PerfCounter niceCPU; + PerfCounter systemCPU; + PerfCounter idleCPU; + CPUData *data; +} CPUInfo; + +typedef struct disk_meta_data +{ + char name[NAME_LEN]; + char mountpoint[NAME_LEN]; +} DiskMetaData; + +typedef struct disk_data +{ + unsigned long long freeMegs; + unsigned int writesPerSec; + unsigned int readsPerSec; +} DiskData; + +typedef struct disk_info +{ + unsigned int numDisks; + DiskMetaData *mdata; + PerfCounter diskObjDesc; + PerfCounter freeMegs; + PerfCounter writesPerSec; + PerfCounter readsPerSec; + DiskData *data; +} DiskInfo; + +typedef struct process_data +{ + unsigned int runningProcessCount; +} ProcessData; + +typedef struct process_info +{ + PerfCounter processObjDesc; + PerfCounter runningProcessCount; + ProcessData *data; +} ProcessInfo; + +typedef struct perf_data_block +{ + unsigned int counter_id; + unsigned int num_counters; + unsigned int NumObjectTypes; + unsigned long long PerfTime; + unsigned long long PerfFreq; + unsigned long long PerfTime100nSec; + MemInfo memInfo; + CPUInfo cpuInfo; + ProcessInfo processInfo; + DiskInfo diskInfo; +} PERF_DATA_BLOCK; + +typedef struct runtime_settings +{ + /* Runtime flags */ + int dflag; + /* DB path names */ + char dbDir[PATH_MAX]; + char nameFile[PATH_MAX]; + char counterFile[PATH_MAX]; + /* TDB context */ + TDB_CONTEXT *cnames; + TDB_CONTEXT *cdata; +} RuntimeSettings; + +/* perf_writer_ng_util.c function prototypes */ +void fatal(char *msg); +void add_key(TDB_CONTEXT *db, char *keystring, char *datastring, int flags); +void add_key_raw(TDB_CONTEXT *db, char *keystring, void *datastring, size_t datasize, int flags); +void make_key(char *buf, int buflen, int key_part1, char *key_part2); +void parse_flags(RuntimeSettings *rt, int argc, char **argv); +void setup_file_paths(RuntimeSettings *rt); +void daemonize(RuntimeSettings *rt); + +/* perf_writer_ng_mem.c function prototypes */ +void get_meminfo(PERF_DATA_BLOCK *data); +void init_memdata_desc(PERF_DATA_BLOCK *data); +void init_memdata(PERF_DATA_BLOCK *data); +void output_mem_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt); +void output_meminfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags); +void init_perf_counter(PerfCounter *counter, PerfCounter *parent, unsigned int index, char *name, char *help, int counter_type, int record_type); + +/* perf_writer_ng_cpu.c function prototypes */ +unsigned long long get_cpufreq(); +void init_cpudata_desc(PERF_DATA_BLOCK *data); +void get_cpuinfo(PERF_DATA_BLOCK *data); +void init_cpu_data(PERF_DATA_BLOCK *data); +void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt); +void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags); + +#endif /* __PERF_H__ */ diff --git a/examples/perfcounter/perf_writer.c b/examples/perfcounter/perf_writer.c new file mode 100644 index 0000000..054d9e8 --- /dev/null +++ b/examples/perfcounter/perf_writer.c @@ -0,0 +1,213 @@ +/* + * Unix SMB/CIFS implementation. + * Performance Counter Daemon + * + * Copyright (C) Marcin Krzysztof Porwit 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "perf.h" + +sig_atomic_t keep_running = TRUE; + +/* allocates memory and gets numCPUs, total memory, and PerfFreq, number of disks... */ +void get_constants(PERF_DATA_BLOCK *data) +{ + data->cpuInfo.numCPUs = sysconf(_SC_NPROCESSORS_ONLN) > 0 ? sysconf(_SC_NPROCESSORS_ONLN) : 1; + data->PerfFreq = sysconf(_SC_CLK_TCK); + init_mem_data(data); + init_cpu_data(data); + init_process_data(data); + init_disk_data(data); + + return; +} + +void output_num_instances(PerfCounter obj, int numInst, RuntimeSettings rt) +{ + char key[NAME_LEN]; + char sdata[NAME_LEN]; + + make_key(key, NAME_LEN, obj.index, "inst"); + memset(sdata, 0, NAME_LEN); + sprintf(sdata, "%d", numInst); + add_key(rt.cnames, key, sdata, TDB_INSERT); + + return; +} + +void output_perf_desc(PerfCounter counter, RuntimeSettings rt) +{ + char key[NAME_LEN]; + char sdata[NAME_LEN]; + + /* First insert the counter name */ + make_key(key, NAME_LEN, counter.index, NULL); + add_key(rt.cnames, key, counter.name, TDB_INSERT); + /* Add the help string */ + make_key(key, NAME_LEN, counter.index + 1, NULL); + add_key(rt.cnames, key, counter.help, TDB_INSERT); + /* Add the relationships */ + make_key(key, NAME_LEN, counter.index, "rel"); + add_key(rt.cnames, key, counter.relationships, TDB_INSERT); + /* Add type data if not PERF_OBJECT or PERF_INSTANCE */ + if(counter.record_type == PERF_COUNTER) + { + make_key(key, NAME_LEN, counter.index, "type"); + memset(sdata, 0, NAME_LEN); + sprintf(sdata, "%d", counter.counter_type); + add_key(rt.cnames, key, sdata, TDB_INSERT); + } + + return; +} + +void initialize(PERF_DATA_BLOCK *data, RuntimeSettings *rt, int argc, char **argv) +{ + memset(data, 0, sizeof(*data)); + memset(rt, 0, sizeof(*rt)); + + parse_flags(rt, argc, argv); + setup_file_paths(rt); + + get_constants(data); + + if(rt->dflag == TRUE) + daemonize(rt); + + output_mem_desc(data, *rt); + output_cpu_desc(data, *rt); + output_process_desc(data, *rt); + output_disk_desc(data, *rt); + + return; +} + +void refresh_perf_data_block(PERF_DATA_BLOCK *data, RuntimeSettings rt) +{ + data->PerfTime100nSec = 0; + get_meminfo(data); + get_cpuinfo(data); + get_processinfo(data); + get_diskinfo(data); + return; +} + +void output_perf_counter(PerfCounter counter, unsigned long long data, + RuntimeSettings rt, int tdb_flags) +{ + char key[NAME_LEN]; + char sdata[NAME_LEN]; + unsigned int size_mask; + + make_key(key, NAME_LEN, counter.index, NULL); + memset(sdata, 0, NAME_LEN); + + size_mask = counter.counter_type & PERF_SIZE_VARIABLE_LEN; + + if(size_mask == PERF_SIZE_DWORD) + sprintf(sdata, "%d", (unsigned int)data); + else if(size_mask == PERF_SIZE_LARGE) + sprintf(sdata, "%Lu", data); + + add_key(rt.cdata, key, sdata, tdb_flags); + + return; +} + +void output_perf_instance(int parentObjInd, + int instanceInd, + void *instData, + size_t dsize, + char *name, + RuntimeSettings rt, + int tdb_flags) +{ + char key[NAME_LEN]; + char sdata[NAME_LEN]; + + memset(key, 0, NAME_LEN); + sprintf(key, "%di%d", parentObjInd, instanceInd); + add_key_raw(rt.cdata, key, instData, dsize, tdb_flags); + + /* encode name */ + memset(key, 0, NAME_LEN); + sprintf(key, "%di%dname", parentObjInd, instanceInd); + add_key(rt.cnames, key, name, tdb_flags); + + return; +} + +void output_global_data(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags) +{ + int i; + char key[NAME_LEN]; + char sdata[NAME_LEN]; + + /* Initialize BaseIndex */ + make_key(key, NAME_LEN, 1, NULL); + memset(sdata, 0, NAME_LEN); + sprintf(sdata, "%d", data->num_counters); + add_key(rt.cnames, key, sdata, tdb_flags); + /* Initialize PerfTime, PerfFreq and PerfTime100nSec */ + memset(sdata, 0, NAME_LEN); + make_key(key, NAME_LEN, 0, "PerfTime"); + sprintf(sdata, "%Lu", data->PerfTime); + add_key(rt.cdata, key, sdata, tdb_flags); + make_key(key, NAME_LEN, 0, "PerfTime100nSec"); + memset(sdata, 0, NAME_LEN); + sprintf(sdata, "%Lu", data->PerfTime100nSec); + add_key(rt.cdata, key, sdata, tdb_flags); + memset(sdata, 0, NAME_LEN); + make_key(key, NAME_LEN, 0, "PerfFreq"); + sprintf(sdata, "%Lu", data->PerfFreq); + add_key(rt.cnames, key, sdata, tdb_flags); + + return; +} + +void output_perf_data_block(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags) +{ + output_global_data(data, rt, tdb_flags); + output_meminfo(data, rt, tdb_flags); + output_cpuinfo(data, rt, tdb_flags); + output_processinfo(data, rt, tdb_flags); + output_diskinfo(data, rt, tdb_flags); + return; +} + +void update_counters(PERF_DATA_BLOCK *data, RuntimeSettings rt) +{ + refresh_perf_data_block(data, rt); + output_perf_data_block(data, rt, TDB_REPLACE); + + return; +} + +int main(int argc, char **argv) +{ + PERF_DATA_BLOCK data; + RuntimeSettings rt; + + initialize(&data, &rt, argc, argv); + + while(keep_running) + { + update_counters(&data, rt); + sleep(1); + } + + return 0; +} diff --git a/examples/perfcounter/perf_writer_cpu.c b/examples/perfcounter/perf_writer_cpu.c new file mode 100644 index 0000000..215e073 --- /dev/null +++ b/examples/perfcounter/perf_writer_cpu.c @@ -0,0 +1,189 @@ +/* + * Unix SMB/CIFS implementation. + * Performance Counter Daemon + * + * Copyright (C) Marcin Krzysztof Porwit 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "perf.h" + +void init_cpudata_desc(PERF_DATA_BLOCK *data) +{ + init_perf_counter(&(data->cpuInfo.cpuObjDesc), + &(data->cpuInfo.cpuObjDesc), + get_counter_id(data), + "Processor", + "The Processor object consists of counters that describe the behavior of the CPU.", + 0, + PERF_OBJECT); + init_perf_counter(&(data->cpuInfo.userCPU), + &(data->cpuInfo.cpuObjDesc), + get_counter_id(data), + "\% User CPU Utilization", + "\% User CPU Utilization is the percentage of the CPU used by processes executing user code.", + PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT, + PERF_COUNTER); + init_perf_counter(&(data->cpuInfo.systemCPU), + &(data->cpuInfo.cpuObjDesc), + get_counter_id(data), + "\% System CPU Utilization", + "\% System CPU Utilization is the percentage of the CPU used by processes doing system calls.", + PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT, + PERF_COUNTER); + init_perf_counter(&(data->cpuInfo.niceCPU), + &(data->cpuInfo.cpuObjDesc), + get_counter_id(data), + "\% Nice CPU Utilization", + "\% Nice CPU Utilization is the percentage of the CPU used by processes running in nice mode.", + PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW, + PERF_COUNTER); + init_perf_counter(&(data->cpuInfo.idleCPU), + &(data->cpuInfo.cpuObjDesc), + get_counter_id(data), + "\% Idle CPU", + "\% Idle CPU is the percentage of the CPU not doing any work.", + PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW, + PERF_COUNTER); + + return; +} + +void get_cpuinfo(PERF_DATA_BLOCK *data) +{ + int num, i; + unsigned int cpuid; + char buf[PROC_BUF]; + static FILE *fp = NULL; + + if(!fp) + { + if(!(fp = fopen("/proc/stat", "r"))) + { + perror("get_cpuinfo: fopen"); + exit(1); + } + } + + rewind(fp); + fflush(fp); + + /* Read in the first line and discard it -- that has the CPU summary */ + if(!fgets(buf, sizeof(buf), fp)) + { + perror("get_cpuinfo: fgets"); + exit(1); + } + for(i = 0; i < data->cpuInfo.numCPUs; i++) + { + if(!fgets(buf, sizeof(buf), fp)) + { + perror("get_cpuinfo: fgets"); + exit(1); + } + num = sscanf(buf, "cpu%u %Lu %Lu %Lu %Lu", + &cpuid, + &data->cpuInfo.data[i].user, + &data->cpuInfo.data[i].nice, + &data->cpuInfo.data[i].system, + &data->cpuInfo.data[i].idle); + if(i != cpuid) + { + perror("get_cpuinfo: /proc/stat inconsistent?"); + exit(1); + } + /* + Alternate way of doing things: + struct tms buffer; + data->PerfTime100nSec = times(&buffer); + */ + data->PerfTime100nSec += data->cpuInfo.data[i].user + + data->cpuInfo.data[i].nice + + data->cpuInfo.data[i].system + + data->cpuInfo.data[i].idle; + } + data->PerfTime100nSec /= data->cpuInfo.numCPUs; + return; +} + +void init_cpu_data(PERF_DATA_BLOCK *data) +{ + data->cpuInfo.data = calloc(data->cpuInfo.numCPUs, sizeof(*data->cpuInfo.data)); + if(!data->cpuInfo.data) + { + perror("init_cpu_data: out of memory"); + exit(1); + } + + init_cpudata_desc(data); + + get_cpuinfo(data); + + return; +} + +void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt) +{ + output_perf_desc(data->cpuInfo.cpuObjDesc, rt); + output_perf_desc(data->cpuInfo.userCPU, rt); + output_perf_desc(data->cpuInfo.niceCPU, rt); + output_perf_desc(data->cpuInfo.systemCPU, rt); + output_perf_desc(data->cpuInfo.idleCPU, rt); + if(data->cpuInfo.numCPUs > 1) + output_num_instances(data->cpuInfo.cpuObjDesc, data->cpuInfo.numCPUs + 1, rt); + + return; +} + +void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags) +{ + int i; + char buf[NAME_LEN]; + + output_perf_counter(data->cpuInfo.userCPU, + data->cpuInfo.data[0].user, + rt, tdb_flags); + output_perf_counter(data->cpuInfo.systemCPU, + data->cpuInfo.data[0].system, + rt, tdb_flags); + output_perf_counter(data->cpuInfo.niceCPU, + data->cpuInfo.data[0].nice, + rt, tdb_flags); + output_perf_counter(data->cpuInfo.idleCPU, + data->cpuInfo.data[0].idle, + rt, tdb_flags); + if(data->cpuInfo.numCPUs > 1) + { + for(i = 0; i < data->cpuInfo.numCPUs; i++) + { + memset(buf, 0, NAME_LEN); + sprintf(buf, "cpu%d", i); + output_perf_instance(data->cpuInfo.cpuObjDesc.index, + i, + (void *)&(data->cpuInfo.data[i]), + sizeof(data->cpuInfo.data[i]), + buf, rt, tdb_flags); + } + + memset(buf, 0, NAME_LEN); + sprintf(buf, "_Total"); + output_perf_instance(data->cpuInfo.cpuObjDesc.index, + i, + (void *)&(data->cpuInfo.data[i]), + sizeof(data->cpuInfo.data[i]), + buf, rt, tdb_flags); + } + return; +} diff --git a/examples/perfcounter/perf_writer_disk.c b/examples/perfcounter/perf_writer_disk.c new file mode 100644 index 0000000..18a63a4 --- /dev/null +++ b/examples/perfcounter/perf_writer_disk.c @@ -0,0 +1,224 @@ +/* + * Unix SMB/CIFS implementation. + * Performance Counter Daemon + * + * Copyright (C) Marcin Krzysztof Porwit 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "perf.h" + +void init_diskdata_desc(PERF_DATA_BLOCK *data) +{ + init_perf_counter(&(data->diskInfo.diskObjDesc), + &(data->diskInfo.diskObjDesc), + get_counter_id(data), + "Logical Disk", + "The Logical Disk object consists of counters that show information about disks.", + 0, + PERF_OBJECT); + init_perf_counter(&(data->diskInfo.freeMegs), + &(data->diskInfo.diskObjDesc), + get_counter_id(data), + "Megabytes Free", + "The amount of available disk space, in megabytes.", + PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX, + PERF_COUNTER); + init_perf_counter(&(data->diskInfo.writesPerSec), + &(data->diskInfo.diskObjDesc), + get_counter_id(data), + "Writes/sec", + "The number of writes per second to that disk.", + PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC, + PERF_COUNTER); + init_perf_counter(&(data->diskInfo.readsPerSec), + &(data->diskInfo.diskObjDesc), + get_counter_id(data), + "Reads/sec", + "The number of reads of that disk per second.", + PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC, + PERF_COUNTER); + + return; +} +void init_num_disks(PERF_DATA_BLOCK *data) +{ + FILE *mtab; + char buf[PROC_BUF]; + char *start, *stop; + int i = 0, num; + + if(!(mtab = fopen("/etc/mtab", "r"))) + { + perror("init_disk_names: fopen"); + exit(1); + } + + rewind(mtab); + fflush(mtab); + + while(fgets(buf, sizeof(buf), mtab)) + { + if(start = strstr(buf, "/dev/")) + { + if(start = strstr(start, "da")) + { + i++; + } + } + } + + data->diskInfo.numDisks = i; + fclose(mtab); + + return; +} + +void init_disk_names(PERF_DATA_BLOCK *data) +{ + FILE *mtab; + char buf[PROC_BUF]; + char *start, *stop; + int i = 0, num; + + if(!(mtab = fopen("/etc/mtab", "r"))) + { + perror("init_disk_names: fopen"); + exit(1); + } + + rewind(mtab); + fflush(mtab); + + while(fgets(buf, sizeof(buf), mtab)) + { + if(start = strstr(buf, "/dev/")) + { + if(start = strstr(start, "da")) + { + start -=1; + stop = strstr(start, " "); + memcpy(data->diskInfo.mdata[i].name, start, stop - start); + start = stop +1; + stop = strstr(start, " "); + memcpy(data->diskInfo.mdata[i].mountpoint, start, stop - start); + i++; + } + } + } + + fclose(mtab); + + return; +} + +void get_diskinfo(PERF_DATA_BLOCK *data) +{ + int i; + DiskData *p; + struct statfs statfsbuf; + int status, num; + char buf[LARGE_BUF], *start; + FILE *diskstats; + unsigned long reads, writes, discard; + + diskstats = fopen("/proc/diskstats", "r"); + rewind(diskstats); + fflush(diskstats); + status = fread(buf, sizeof(char), LARGE_BUF, diskstats); + fclose(diskstats); + + for(i = 0; i < data->diskInfo.numDisks; i++) + { + p = &(data->diskInfo.data[i]); + status = statfs(data->diskInfo.mdata[i].mountpoint, &statfsbuf); + p->freeMegs = (statfsbuf.f_bfree*statfsbuf.f_bsize)/1048576; + start = strstr(buf, data->diskInfo.mdata[i].name); + start += strlen(data->diskInfo.mdata[i].name) + 1; + num = sscanf(start, "%lu %lu %lu %lu", + &reads, + &discard, + &writes, + &discard); + p->writesPerSec = writes; + p->readsPerSec = reads; + fprintf(stderr, "%s:\t%u\t%u\n", + data->diskInfo.mdata[i].mountpoint, + reads, writes); + } + return; +} +void init_disk_data(PERF_DATA_BLOCK *data) +{ + init_diskdata_desc(data); + + init_num_disks(data); + + data->diskInfo.mdata = calloc(data->diskInfo.numDisks, sizeof(DiskMetaData)); + if(!data->diskInfo.mdata) + { + fatal("init_disk_data: out of memory"); + } + + init_disk_names(data); + + data->diskInfo.data = calloc(data->diskInfo.numDisks, sizeof(DiskData)); + if(!data->diskInfo.data) + { + fatal("init_disk_data: out of memory"); + } + + get_diskinfo(data); + + return; +} + +void output_disk_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt) +{ + output_perf_desc(data->diskInfo.diskObjDesc, rt); + output_perf_desc(data->diskInfo.freeMegs, rt); + output_perf_desc(data->diskInfo.writesPerSec, rt); + output_perf_desc(data->diskInfo.readsPerSec, rt); + output_num_instances(data->diskInfo.diskObjDesc, data->diskInfo.numDisks, rt); + + return; +} + +void output_diskinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags) +{ + int i; + + output_perf_counter(data->diskInfo.freeMegs, + data->diskInfo.data[0].freeMegs, + rt, tdb_flags); + output_perf_counter(data->diskInfo.writesPerSec, + (unsigned long long)data->diskInfo.data[0].writesPerSec, + rt, tdb_flags); + output_perf_counter(data->diskInfo.readsPerSec, + (unsigned long long)data->diskInfo.data[0].readsPerSec, + rt, tdb_flags); + + for(i = 0; i < data->diskInfo.numDisks; i++) + { + output_perf_instance(data->diskInfo.diskObjDesc.index, + i, + (void *)&(data->diskInfo.data[i]), + sizeof(DiskData), + data->diskInfo.mdata[i].mountpoint, + rt, tdb_flags); + } + + return; +} diff --git a/examples/perfcounter/perf_writer_mem.c b/examples/perfcounter/perf_writer_mem.c new file mode 100644 index 0000000..580207f --- /dev/null +++ b/examples/perfcounter/perf_writer_mem.c @@ -0,0 +1,124 @@ +/* + * Unix SMB/CIFS implementation. + * Performance Counter Daemon + * + * Copyright (C) Marcin Krzysztof Porwit 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "perf.h" + +void get_meminfo(PERF_DATA_BLOCK *data) +{ + int status; + struct sysinfo info; + status = sysinfo(&info); + + data->memInfo.data->availPhysKb = (info.freeram * info.mem_unit)/1024; + data->memInfo.data->availSwapKb = (info.freeswap * info.mem_unit)/1024; + data->memInfo.data->totalPhysKb = (info.totalram * info.mem_unit)/1024; + data->memInfo.data->totalSwapKb = (info.totalswap * info.mem_unit)/1024; + + /* Also get uptime since we have the structure */ + data->PerfTime = (unsigned long)info.uptime; + + return; +} + +void init_memdata_desc(PERF_DATA_BLOCK *data) +{ + init_perf_counter(&(data->memInfo.memObjDesc), + &(data->memInfo.memObjDesc), + get_counter_id(data), + "Memory", + "The Memory performance object consists of counters that describe the behavior of physical and virtual memory on the computer.", + 0, + PERF_OBJECT); + init_perf_counter(&(data->memInfo.availPhysKb), + &(data->memInfo.memObjDesc), + get_counter_id(data), + "Available Physical Kilobytes", + "Available Physical Kilobytes is the number of free kilobytes in physical memory", + PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX, + PERF_COUNTER); + init_perf_counter(&(data->memInfo.availSwapKb), + &(data->memInfo.memObjDesc), + get_counter_id(data), + "Available Swap Kilobytes", + "Available Swap Kilobytes is the number of free kilobytes in swap space", + PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX, + PERF_COUNTER); + init_perf_counter(&(data->memInfo.totalPhysKb), + &(data->memInfo.memObjDesc), + get_counter_id(data), + "Total Physical Kilobytes", + "Total Physical Kilobytes is a base counter", + PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW, + PERF_COUNTER); + init_perf_counter(&(data->memInfo.totalSwapKb), + &(data->memInfo.memObjDesc), + get_counter_id(data), + "Total Swap Kilobytes", + "Total Swap Kilobytes is a base counter", + PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW, + PERF_COUNTER); + + return; +} + +void init_mem_data(PERF_DATA_BLOCK *data) +{ + data->memInfo.data = calloc(1, sizeof(*data->memInfo.data)); + if(!data->memInfo.data) + { + perror("init_memdata: out of memory"); + exit(1); + } + + init_memdata_desc(data); + + get_meminfo(data); + + return; +} + +void output_mem_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt) +{ + output_perf_desc(data->memInfo.memObjDesc, rt); + output_perf_desc(data->memInfo.availPhysKb, rt); + output_perf_desc(data->memInfo.availSwapKb, rt); + output_perf_desc(data->memInfo.totalPhysKb, rt); + output_perf_desc(data->memInfo.totalSwapKb, rt); + + return; +} + +void output_meminfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags) +{ + output_perf_counter(data->memInfo.availPhysKb, + (unsigned long long)data->memInfo.data->availPhysKb, + rt, tdb_flags); + output_perf_counter(data->memInfo.availSwapKb, + (unsigned long long)data->memInfo.data->availSwapKb, + rt, tdb_flags); + output_perf_counter(data->memInfo.totalPhysKb, + (unsigned long long)data->memInfo.data->totalPhysKb, + rt, tdb_flags); + output_perf_counter(data->memInfo.totalSwapKb, + (unsigned long long)data->memInfo.data->totalSwapKb, + rt, tdb_flags); + + return; +} diff --git a/examples/perfcounter/perf_writer_process.c b/examples/perfcounter/perf_writer_process.c new file mode 100644 index 0000000..bddceea --- /dev/null +++ b/examples/perfcounter/perf_writer_process.c @@ -0,0 +1,85 @@ +/* + * Unix SMB/CIFS implementation. + * Performance Counter Daemon + * + * Copyright (C) Marcin Krzysztof Porwit 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "perf.h" + +void get_processinfo(PERF_DATA_BLOCK *data) +{ + int status; + struct sysinfo info; + status = sysinfo(&info); + + data->processInfo.data->runningProcessCount = (unsigned int)info.procs; + + return; +} + +void init_processdata_desc(PERF_DATA_BLOCK *data) +{ + init_perf_counter(&(data->processInfo.processObjDesc), + &(data->processInfo.processObjDesc), + get_counter_id(data), + "Processes", + "%The Processes performance object displays aggregate information about processes on the machine.", + 0, + PERF_OBJECT); + init_perf_counter(&(data->processInfo.runningProcessCount), + &(data->processInfo.processObjDesc), + get_counter_id(data), + "Process Count", + "Process Count is the number of processes currently on the machine.", + PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX, + PERF_COUNTER); + + return; +} + +void init_process_data(PERF_DATA_BLOCK *data) +{ + data->processInfo.data = calloc(1, sizeof(*data->processInfo.data)); + if(!(data->processInfo.data)) + { + perror("init_process_data: out of memory"); + exit(1); + } + + init_processdata_desc(data); + + get_processinfo(data); + + return; +} + +void output_processinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags) +{ + output_perf_counter(data->processInfo.runningProcessCount, + (unsigned long long)data->processInfo.data->runningProcessCount, + rt, tdb_flags); + + return; +} + +void output_process_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt) +{ + output_perf_desc(data->processInfo.processObjDesc, rt); + output_perf_desc(data->processInfo.runningProcessCount, rt); + + return; +} diff --git a/examples/perfcounter/perf_writer_util.c b/examples/perfcounter/perf_writer_util.c new file mode 100644 index 0000000..6f1eb16 --- /dev/null +++ b/examples/perfcounter/perf_writer_util.c @@ -0,0 +1,235 @@ +/* + * Unix SMB/CIFS implementation. + * Performance Counter Daemon + * + * Copyright (C) Marcin Krzysztof Porwit 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "perf.h" + +extern sig_atomic_t keep_running; + +void fatal(char *msg) +{ + perror(msg); + exit(1); +} + +void add_key_raw(TDB_CONTEXT *db, char *keystring, void *databuf, size_t datasize, int flags) +{ + TDB_DATA key, data; + + key.dptr = keystring; + key.dsize = strlen(keystring); + data.dptr = databuf; + data.dsize = datasize; + + tdb_store(db, key, data, flags); +} + +void add_key(TDB_CONTEXT *db, char *keystring, char *datastring, int flags) +{ + TDB_DATA key, data; + + key.dptr = keystring; + key.dsize = strlen(keystring); + data.dptr = datastring; + data.dsize = strlen(datastring); + + tdb_store(db, key, data, flags); +} + +void make_key(char *buf, int buflen, int key_part1, char *key_part2) +{ + memset(buf, 0, buflen); + if(key_part2 != NULL) + sprintf(buf, "%d%s", key_part1, key_part2); + else + sprintf(buf, "%d", key_part1); + + return; +} + +void usage(char *progname) +{ + fprintf(stderr, "Usage: %s [-d] [-f <file_path>].\n", progname); + fprintf(stderr, "\t-d: run as a daemon.\n"); + fprintf(stderr, "\t-f <file_path>: path where the TDB files reside.\n"); + fprintf(stderr, "\t\tDEFAULT is /var/lib/samba/perfmon\n"); + exit(1); +} + +void parse_flags(RuntimeSettings *rt, int argc, char **argv) +{ + int flag; + + while((flag = getopt(argc, argv, "df:")) != -1) + { + switch(flag) + { + case 'd': + { + rt->dflag = TRUE; + break; + } + case 'f': + { + memcpy(rt->dbDir, optarg, strlen(optarg)); + break; + } + default: + { + usage(argv[0]); + } + } + } + + return; +} + +void setup_file_paths(RuntimeSettings *rt) +{ + int status; + + if(strlen(rt->dbDir) == 0) + { + /* No file path was passed in, use default */ + sprintf(rt->dbDir, "/var/lib/samba/perfmon"); + } + + sprintf(rt->nameFile, "%s/names.tdb", rt->dbDir); + sprintf(rt->counterFile, "%s/data.tdb", rt->dbDir); + + mkdir(rt->dbDir, 0755); + rt->cnames = tdb_open(rt->nameFile, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644); + rt->cdata = tdb_open(rt->counterFile, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644); + + if(rt->cnames == NULL || rt->cdata == NULL) + { + perror("setup_file_paths"); + exit(1); + } + + return; +} + +void sigterm_handler() +{ + keep_running = FALSE; + return; +} + +void daemonize(RuntimeSettings *rt) +{ + pid_t pid; + int i; + int fd; + + /* Check if we're already a daemon */ + if(getppid() == 1) + return; + pid = fork(); + if(pid < 0) + /* can't fork */ + exit(1); + else if(pid > 0) + { + /* we're the parent */ + tdb_close(rt->cnames); + tdb_close(rt->cdata); + exit(0); + } + + /* get a new session */ + if(setsid() == -1) + exit(2); + + /* Change CWD */ + chdir("/"); + + /* close file descriptors */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + /* And reopen them as safe defaults */ + fd = open("/dev/null", O_RDONLY); + if(fd != 0) + { + dup2(fd, 0); + close(fd); + } + fd = open("/dev/null", O_WRONLY); + if(fd != 1) + { + dup2(fd, 1); + close(fd); + } + fd = open("/dev/null", O_WRONLY); + if(fd != 2) + { + dup2(fd, 2); + close(fd); + } + + /* handle signals */ + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGTERM, sigterm_handler); + + return; +} + +int get_counter_id(PERF_DATA_BLOCK *data) +{ + data->counter_id += 2; + data->num_counters++; + + return data->counter_id; +} + +void init_perf_counter(PerfCounter *counter, + PerfCounter *parent, + unsigned int index, + char *name, + char *help, + int counter_type, + int record_type) +{ + counter->index = index; + memcpy(counter->name, name, strlen(name)); + memcpy(counter->help, help, strlen(help)); + counter->counter_type = counter_type; + counter->record_type = record_type; + + switch(record_type) + { + case PERF_OBJECT: + sprintf(counter->relationships, "p"); + break; + case PERF_COUNTER: + sprintf(counter->relationships, "c[%d]", parent->index); + break; + case PERF_INSTANCE: + sprintf(counter->relationships, "i[%d]", parent->index); + break; + default: + perror("init_perf_counter: unknown record type"); + exit(1); + } + + return; +} diff --git a/examples/perfcounter/perfcountd.init b/examples/perfcounter/perfcountd.init new file mode 100755 index 0000000..0beff96 --- /dev/null +++ b/examples/perfcounter/perfcountd.init @@ -0,0 +1,65 @@ +#!/bin/sh +# +# Copyright (C) Gerald Carter 2005 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <http://www.gnu.org/licenses/>. +# +#################################################################### + +## This file should have uid root, gid sys and chmod 744 + +PATH=/bin:/usr/bin:/sbin:/usr/sbin + +killproc() +{ + pid=`ps aux | grep $1 | egrep -v '(grep|perfcountd)' | awk '{print $2}'` + if [ x"$pid" != "x" ]; then + kill $pid + fi +} + +# Start/stop processes + +case "$1" +in +start) + /opt/samba/bin/perfcount -d -f /var/lib/samba/perfmon 2> /dev/null + if [ $? -ne 0 ]; then + echo "Failed!" + exit 1 + fi + echo "done!" + ;; +stop) + killproc perfcount + ;; + +status) + pid=`ps aux | grep perfcount | egrep -v '(grep|perfcountd)' | awk '{print $2}'` + if [ x"$pid" = "x" ]; then + echo "Dead!" + exit 2; + fi + echo "OK!" + ;; +restart) + $0 stop && $0 start + ;; + +*) + echo "Usage: $0 { start|stop|restart|status }" + ;; +esac + + diff --git a/examples/printer-accounting/README b/examples/printer-accounting/README new file mode 100644 index 0000000..b7ab42a --- /dev/null +++ b/examples/printer-accounting/README @@ -0,0 +1,63 @@ +These are just a few examples of what you can do for printer accounting; +they are really just hacks to show a manager how may pages were being +printed out on his new hp5n :) + +acct-all will run acct-sum and read the log files to generate some +stats. + +Here is a sample output of the raw stats : + +1996-06-10.15:02:15 pkelly master.fcp.oypi.com 538 0 +1996-06-10.15:06:40 pkelly master.fcp.oypi.com 537 0 +1996-06-10.15:32:12 ted master.fcp.oypi.com 547 0 +1996-06-11.09:06:15 violet master.fcp.oypi.com 2667 0 +1996-06-11.09:48:02 violet master.fcp.oypi.com 66304 5 +1996-06-11.09:50:04 violet master.fcp.oypi.com 116975 9 +1996-06-11.09:57:20 violet master.fcp.oypi.com 3013 1 +1996-06-11.10:13:17 pkelly master.fcp.oypi.com 3407 1 +1996-06-11.12:37:06 craig master.fcp.oypi.com 13639 2 +1996-06-11.12:42:23 pkelly master.fcp.oypi.com 13639 2 +1996-06-11.12:45:11 marlene master.fcp.oypi.com 515 0 +1996-06-11.14:17:10 lucie master.fcp.oypi.com 1405 1 +1996-06-11.14:36:03 laura master.fcp.oypi.com 45486 5 +1996-06-11.15:08:21 violet master.fcp.oypi.com 1923 1 +1996-06-11.15:09:42 laura master.fcp.oypi.com 4821 1 +1996-06-11.15:12:28 laura master.fcp.oypi.com 46277 5 +1996-06-11.15:19:38 violet master.fcp.oypi.com 3503 1 +1996-06-11.15:21:49 lucie master.fcp.oypi.com 493 0 +1996-06-11.15:43:36 al master.fcp.oypi.com 3067 1 + +And the output after the acct-sum is done on a full set of files +in /var/log/lp/* + +master[1072] /var/log/lp$ /etc/conf/acct-all + +Sun Jul 21 23:03:16 EDT 1996 + +Pages are approximate ... + +User Jobs Pages Size +al 1 1 2 KB +craig 1 2 13 KB +jack 68 235 1995 KB +laura 88 328 3050 KB +lucie 221 379 3529 KB +marlene 12 151 1539 KB +melanie 83 365 3691 KB +michelle 68 219 1987 KB +mike 2 10 81 KB +neil 111 225 2753 KB +operator 44 137 1132 KB +pkelly 368 984 11154 KB +root 8 0 29 KB +ted 158 257 2337 KB +tony 244 368 2455 KB +violet 419 1002 10072 KB + + +Printer Jobs Pages +hp2p 3 4 +hp5 915 2135 +lp 978 2524 + +<pkelly@ets.net> diff --git a/examples/printer-accounting/acct-all b/examples/printer-accounting/acct-all new file mode 100644 index 0000000..dc8f175 --- /dev/null +++ b/examples/printer-accounting/acct-all @@ -0,0 +1,9 @@ +#!/bin/sh + +echo "" +date +echo "" +echo "Pages are approximate ..." +echo "" +/etc/conf/acct-sum /var/log/lp/* +echo "" diff --git a/examples/printer-accounting/acct-sum b/examples/printer-accounting/acct-sum new file mode 100644 index 0000000..ffbfc8d --- /dev/null +++ b/examples/printer-accounting/acct-sum @@ -0,0 +1,29 @@ +#!/usr/bin/perl + +while (<>) { + ($date, $user, $machine, $size, $pages) = split(' '); + + $Printer{$ARGV}++; + $PrinterPages{$ARGV} += $pages; + + $Jobs{$user}++; + $Size{$user}+= $size; + $Pages{$user}+= $pages; +} + +printf "%-15s %5s %8s %8s\n", qw(User Jobs Pages Size); +foreach $user (sort keys %Jobs) { + printf "%-15s %5d %8d %8d \KB\n", + $user, $Jobs{$user}, $Pages{$user}, $Size{$user}/1024; +} + + +print "\n\n"; +printf "%-15s %5s %8s %8s\n", qw(Printer Jobs Pages); +foreach $prn (sort keys %Printer) { + ($name = $prn) =~ s=.*/==; + printf "%-15s %5d %8d\n", + $name, $Printer{$prn}, $PrinterPages{$prn}; +} + + diff --git a/examples/printer-accounting/hp5-redir b/examples/printer-accounting/hp5-redir new file mode 100644 index 0000000..e23f718 --- /dev/null +++ b/examples/printer-accounting/hp5-redir @@ -0,0 +1,40 @@ +#!/usr/bin/perl +# +# 0 == stdin == document +# 1 == stdout == printer +# 2 == stderr == logging +# +# With redirection to another valid /etc/printcap entry +# + +umask(002); + +# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct +require "getopts.pl"; +&Getopts("w:l:i:n:h:"); + +chomp($date = `date '+%Y-%m-%d.%T'`); + +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks) + = stat(STDIN); + +# send to the real printer now. +open(P, "|lpr -Pmgmt0") || die "Can't print to hp5-real ($!)\n"; +$cnt = 0; +while (sysread(STDIN, $buf, 10240)) { + print P $buf; + # this is ugly, but it gives the approx in pages. We + # don't print graphics, so ... There must be a better way :) + $cnt += ($buf =~ /^L/g); +} +close(P); + +$acct = shift; +if (open(ACCT, ">>$acct")) { + print ACCT "$date $opt_n $opt_h $size $cnt\n"; + close(ACCT); +} else { + warn "Err: Can't account for it ($!)\n"; + warn "Log: $date $opt_n $opt_h $size $cnt\n"; +} diff --git a/examples/printer-accounting/lp-acct b/examples/printer-accounting/lp-acct new file mode 100644 index 0000000..3acdbb9 --- /dev/null +++ b/examples/printer-accounting/lp-acct @@ -0,0 +1,35 @@ +#!/usr/bin/perl +# +# 0 == stdin == document +# 1 == stdout == printer +# 2 == stderr == logging +# +# Regular, with no redirection +# + +umask(002); + +# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct +require "getopts.pl"; +&Getopts("w:l:i:n:h:"); + +chomp($date = `date '+%Y-%m-%d.%T'`); + +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks) + = stat(STDIN); + +$cnt = 0; +while (sysread(STDIN, $buf, 10240)) { + print $buf; + $cnt += ($buf =~ /^L/g); +} + +$acct = shift; +if (open(ACCT, ">>$acct")) { + print ACCT "$date $opt_n $opt_h $size $cnt\n"; + close(ACCT); +} else { + warn "Err: Can't account for it ($!)\n"; + warn "Log: $date $opt_n $opt_h $size $cnt\n"; +} diff --git a/examples/printer-accounting/printcap b/examples/printer-accounting/printcap new file mode 100644 index 0000000..976005a --- /dev/null +++ b/examples/printer-accounting/printcap @@ -0,0 +1,22 @@ +# HP5N - Accounting entry +# +# This file calls the filter, hp5-redir to do the numbers and then +# is redirected to the real entry, mgmt0, which is a remote HP5N +# on the LAN with it's own IP number. +# +hp5:lp=/dev/lp1:\ + :sd=/usr/spool/lpd/hp5-acct:\ + :lf=/var/log/lp-err:\ + :af=/var/log/lp/hp5:\ + :if=/usr/local/bin/lp/hp5-redir:\ + :sh:sf:\ + :mx#0: + +# HP5N - Real printer location +mgmt0:\ + :rm=hp5.fcp.oypi.com:\ + :rp=hp5.fcp.oypi.com:\ + :sd=/usr/spool/lpd/mgmt0:\ + :sh:sf:\ + :mx#0: + diff --git a/examples/printing/VampireDriversFunctions b/examples/printing/VampireDriversFunctions new file mode 100644 index 0000000..b06e365 --- /dev/null +++ b/examples/printing/VampireDriversFunctions @@ -0,0 +1,1656 @@ +#!/bin/bash + +##################################################################### +## +## smb.conf parser class +## +## Copyright (C) Kurt Pfeifle <kpfeifle@danka.de>, 2004. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## +###################################################################### + +###################################################################### +## Here an example calling sequence +##!/bin/sh +## set -x +## source VampireDriversFunctions + +## +## Start local variables +## +## You must define these variable (possibly in a source script) + +## nthost=192.168.17.1 +## printeradmin=Administrator +## adminpasswd=not4you + +## smbhost=knoppix +## smbprinteradmin=knoppix +## smbadminpasswd=knoppix +## +## End of local variables +## + +## +## functions to call +## + +## fetchenumdrivers3listfromNThost # repeat, if no success at first +## createdrivernamelist +## createprinterlistwithUNCnames # repeat, if no success at first +## createmapofprinterstodriver +## splitenumdrivers3list +## makesubdirsforWIN40driverlist +## splitWIN40fileintoindividualdriverfiles +## fetchtheWIN40driverfiles +## uploadallWIN40drivers +## makesubdirsforW32X86driverlist +## splitW32X86fileintoindividualdriverfiles +## fetchtheW32X86driverfiles +## uploadallW32X86drivers + +## End of example calling sequence +###################################################################### + + +# ----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- +function vampiredrivers_readme() +{ +echo -e " \n\ +############################################################################ +# +# About the \"Vampire Printer Drivers\" set of functions.... +# -------------------------------------------------------- +# +# (C) Kurt Pfeifle <kpfeifle@danka.de>, 2004 +# License: GPL +# +# ------------------------------------------------------------ +# +# Version: 0.8 (largely \"self-documented\" now, but not yet +# completely -- if it ever will be....) +# +# Thanks a lot to Fabian Franz for helping me with some important +# Bash-Scripting-Questions! +# +# This set of functions provides a framework to snatch all printer +# driver info and related files from a Windows NT print server. +# It then uploads and installs the drivers to a Samba server. (The +# Samba server needs to be prepared for this: a valid [print$] +# share, with write access set for a user with SePrintOperatorPrivilege.) +# +# The main commands used are \"smbclient\" and \"rpcclient\" combined +# with \"grep\", \"sed\" and \"awk\". Probably a Perl or Python script +# would be better suited to do this, mainly because we have to cope +# with printer and driver names which are containing spaces in +# them, so a lot of shell escaping is required to handle these. +# Also, I am not very savvy in scripting, so I invented some very +# obscure methods to work around my knowledge gaps. When I download +# the driver files from the Windows NT box, I put all related driver +# files into their own sub directory, using the same name as the +# driver. Also, driver versions \"0\", \"2\" and \"3\" are placed in +# further subdirectories. +# +# +# Known problems: +# --------------- +# +# 1) I found one printer driver containing a \"slash\" which is not +# handled by this script: \"HP Color LaserJet 5/5M PS\". (There +# are more of these in the wild, of course.) -- The reason: I +# didn't find a way to create a Unix directory containing a \"slash\". +# UPDATE: The script replaces the \"/\" with a \"_\" and also renames +# the drivername accordingly, when it is uploaded to the Samba +# [print$] share.... +# +# 2) There is an unsolved problem in case a real file name deviates +# in its case sensitive spelling from how it is displayed by the +# \"rpcclient enumdrivers\" command. I encountered cases where +# rpcclient displayed \"PS5UI.DLL\" as a file name, but \"smbclient +# mget\" retrieved \"ps5ui.dll\" from the NT printserver, and the +# driverinstallation failed because \"smbclient mput\" tried to put +# \"PS5UI.DLL\" back onto the Samba server where UNIX only had +# \"ps5ui.dll\" available (which of course failed). -- UPDATE: this +# is now solved. All files are renamed now to the same +# case-sensitive spelling as \"rpcclient ... enumdrivers 3\" +# announces. This includes renaming into both, uppercase or +# lowercase, as the case might be.... +# +# 3) This script is probably not portable at all and relies on lots +# of Bash-isms. +# +# 4) This script runs with rpcclient from Samba-3.0.2a (or later) only +# (because it uses the \"Version\" parameter for \"adddriver\"). +# +# The following functions use a few external variables to log +# into the 2 hosts. We suggest that you create a file which +# contains the variables and that you source that file at the +# beginning of this script... +# +# ################################################################# +# +# ntprinteradmin=Administrator # any account on the NT host +# # with SePrintOperatorPrivilege privileges +# ntadminpasswd=not4you # the printer admin password on +# # the NT print server +# nthost=windowsntprintserverbox # the netbios name of the NT print +# # server +# +# smbprinteradmin=knoppix # an account on the Samba server +# # with SePrintOperatorPrivilege privileges +# smbadminpasswd=2secret4you # the printer admin password on +# # the Samba server +# smbhost=knoppix # the netbios name of the Samba +# # print server +# +# ################################################################# +# +# +# NOTE: these functions also work for 2 NT print servers: snatch all +# drivers from the first, and upload them to the second server (which +# takes the role of the \"Samba\" server). Of course they also work +# for 2 Samba servers: snatch all drivers from the first (which takes +# the role of the NT print server) and upload them to the second.... +# +# +# ............PRESS \"q\" TO QUIT............" \ +|less +} + + +#set -x + + +# ----------------------------------------------------------------------------- +# ----------- print a little help... ------------------------------------------ +# ----------------------------------------------------------------------------- + +function helpwithvampiredrivers() +{ +if stringinstring help "$@"; then +helpwithvampiredrivers ; +else + echo " "; + echo " 1. Run the functions of this script one by one."; + echo " "; + echo " 2. List all functions with the \"enumallfunctions\" call."; + echo " "; + echo " 3. After each functions' run, check if it completed successfully."; + echo " "; + echo " 4. For each function, you can ask for separate help by typing"; + echo " \"<functionname> --help\"." + echo " "; + echo " 5. Often network conditions prevent the MS-RPC calls" + echo " implemented by Samba to succeed at the first attempt." + echo " You may have more joy if you try more than once or twice...."; + echo " "; + echo " 6. I can not support end-users who have problems with this script." + echo " However, we are available for paid, professional consulting," + echo " training and troubleshooting work."; + echo " "; + echo " "; +fi +} + +# ----------------------------------------------------------------------------- +# ----------- enumerate all builtin functions... ------------------------------ +# ----------------------------------------------------------------------------- +function enumallfunctions() +{ +if stringinstring help "$@"; then +helpwithvampiredrivers ; +else + echo " " + echo " " + echo "--> Running now function enumallfunctions()..." + echo "==============================================" + echo -e " \n\ + + NOTE: run the listed functions in the same order as listed below. + + EXAMPLE: \"knoppix@ttyp6[knoppix]$ helpwithvampiredrivers\" + + HELP: the \"--help\" parameter prints usage hints regarding a function. + + EXAMPLE: \"knoppix@ttyp6[knoppix]$ fetchenumdrivers3listfromNThost --help\" + + + function vampiredrivers_readme() + function enumallfunctions() + function helpwithvampiredrivers() + function fetchenumdrivers3listfromNThost() # repeat, if no success at first + function createdrivernamelist() + function createprinterlistwithUNCnames() # repeat, if no success at first + function createmapofprinterstodrivers() + function splitenumdrivers3list() + function makesubdirsforW32X86driverlist() + function splitW32X86fileintoindividualdriverfiles() + function fetchallW32X86driverfiles() + function uploadallW32X86drivers() + function makesubdirsforWIN40driverlist() + function splitWIN40fileintoindividualdriverfiles() + function fetchallWIN40driverfiles() + function uploadallWIN40drivers()" + echo " " +fi +} + +# this is a helperfunction (Thanks to Fabian Franz!) +function stringinstring() +{ + case "$2" in *$1*) + return 0 + ;; + esac + return 1 +} + +# ----------------------------------------------------------------------------- +# ----------- Create an "enumprinters 3" list --------------------- ----------- +# ----------------------------------------------------------------------------- +# + +function helpwithfetchenumdrivers3listfromNThost() +{ +echo -e " \n\ +################################################################################ +# +# About fetchenumdrivers3listfromNThost().... +# ------------------------------------------- +# +# PRECONDITIONS: 1) This function expects write access to the current directory. +# 2) This function expects to have the '\$nthosts', +# '\$ntprinteradmin' and '\$ntadminpasswd' variables set to +# according values. +# +# WHAT IT DOES: This function connects to the '\$nthost' (using the credentials +# '\$ntprinteradmin' with '\$ntadminpasswd', retrieves a list of +# drivers (with related file names) from that host, and saves the +# list under the name of '\${nthost}/enumdrivers3list.txt' (ie. it +# also creates the '\$nthost' subdirectory in the current one). It +# further prints some more info to stdout. +# +# IF IT DOESN'T WORK: It may happen that the function doesn't work at the first +# time (there may be a connection problem). Just repeat a +# few times. It may work then. You will recognize if it +# does. +# +# HINT: The current values: 'nthost'=\"$nthost\" +# 'ntprinteradmin'=\"$ntprinteradmin\" +# 'ntadminpasswd'=<not shown here, check yourself!> +# +################################################################################" +echo " " +} + +# ----------------------------------------------------------------------------- + +function fetchenumdrivers3listfromNThost() +{ +if stringinstring help "$@"; then +helpwithfetchenumdrivers3listfromNThost; +else + echo " " + echo " " + echo "--> Running now function fetchenumdrivers3listfromNThost" + echo "========================================================" + [ -d ${nthost} ] || mkdir "${nthost}"; + rpcclient -U${ntprinteradmin}%${ntadminpasswd} -c 'enumdrivers 3' ${nthost} \ + | sed -e '/^.*Driver Name: \[.*\]/ y/\//_/' \ + | tee \ + ${nthost}/enumdrivers3list.txt; + + NUMBEROFDIFFERENTDRIVERNAMES=$( grep "Driver Name:" ${nthost}/enumdrivers3list.txt \ + | sort -f \ + | uniq \ + | wc -l ); + + echo " "; + echo "--> Finished in running function fetchenumdrivers3listfromNThost...."; + echo "====================================================================" + echo "NUMBEROFDIFFERENTDRIVERNAMES retrieved from \"${nthost}\" is $NUMBEROFDIFFERENTDRIVERNAMES".; + echo " --> If you got \"0\" you may want to try again. <---"; + echo "================================================================"; + echo " "; + enumdrivers3list=`cat ${nthost}/enumdrivers3list.txt`; +fi +} + + +# ----------------------------------------------------------------------------- +# ----------- Create a list of all available drivers installed ---------------- +# ------------------------on the NT print server------------------------------- +# ----------------------------------------------------------------------------- +# + +function helpwithcreatedrivernamelist() +{ +echo -e " \n\ +################################################################################ +# +# About createdrivernamelist()... +# ------------------------------- +# +# PRECONDITIONS: 1) This function expects to find the subdirectory '\$nthost' +# and the file '\${nthost}/enumdrivers3list.txt' to exist. +# 2) This function expects to have the '\$nthosts' variable set +# to an according value. +# +# WHAT IT DOES: This function dissects the '\${nthost}/enumdrivers3list.txt' +# and creates other textfiles from its contents: +# - '\${nthost}/drvrlst.txt' +# - '\${nthost}/completedriverlist.txt' +# and further prints some more info to stdout. +# +# HINT: The current value: 'nthost'=\"$nthost\" +# +################################################################################" +} + +# ----------------------------------------------------------------------------- + +function createdrivernamelist() +{ +if stringinstring help "$@"; then +helpwithcreatedrivernamelist; +else + echo " "; + echo " "; + echo "--> Running now function createdrivernamelist...."; + echo "================================================="; + cat ${nthost}/enumdrivers3list.txt \ + | grep "Driver Name:" \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | sort -f \ + | uniq \ + | tr / _ \ + | sed -e 's/$/\"/' -e 's/^ */\"/' \ + | tee \ + ${nthost}/drvrlst.txt; + drvrlst=$(echo ${nthost}/drvrlst.txt); + + cat ${nthost}/enumdrivers3list.txt \ + | grep "Driver Name:" \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | sort -f \ + | uniq \ + | sed -e 's/$/\"/' \ + | cat -n \ + | sed -e 's/^ */DRIVERNAME/' -e 's/\t/\="/' \ + | tee \ + ${nthost}/completedriverlist.txt; + + NUMBEROFDRIVERS=`cat ${nthost}/completedriverlist.txt| wc -l`; + echo " "; + echo "--> Finished in running function createdrivernamelist...."; + echo "===============================================================================" + echo "NUMBEROFDRIVERS retrieve-able from \"${nthost}\" is $NUMBEROFDRIVERS".; + echo " --> If you got \"0\" you may want to run \"fetchenumdrivers3listfromNThost\"" + echo " again. <---"; + echo "==============================================================================="; + echo " "; + driverlist=`cat ${nthost}/completedriverlist.txt`; + + # alternative method suggested by Fabian Franz: + # | awk 'BEGIN {n=1} { print "DRIVERNAME"n"=\""$0"\""; n=n+1 } ' +fi +} + + + +# ----------------------------------------------------------------------------- +# ----------- Create a list of all available printers ------------------------- +# ----------------------------------------------------------------------------- +# + +function helpwithcreateprinterlistwithUNCnames() +{ +echo -e " \n\ +################################################################################ +# +# About createprinterlistwithUNCnames()... +# ---------------------------------------- +# +# PRECONDITIONS: 1) This function expects write access to the current directory. +# 2) This function expects to have the '\$nthost', +# '\$ntprinteradmin' and '\$ntadminpasswd' variables set to +# according values. +# +# WHAT IT DOES: This function connects to the '\$nthost' (using the credentials +# '\$ntprinteradmin' with '\$ntadminpasswd'), retrieves a list of +# printqueues (with associated driver names) from that host (with +# the help of the 'rpcclient ... enumprinters' utility, and saves +# it under name and path '\${nthost}/printerlistwithUNCnames.txt' +# (ie. it also creates the '\$nthost' subdirectory in the current +# one). It further prints some more info to stdout. +# +# IF IT DOESN'T WORK: It may happen that the function doesn't work at the first +# time (there may be a connection problem). Just repeat a +# few times. It may work then. You will recognize if it does. +# +# HINT: The current values: 'nthost'=\"$nthost\" +# 'ntprinteradmin'=\"$ntprinteradmin\" +# 'ntadminpasswd'=<not shown here, check yourself!> +# +################################################################################" +} + +# ----------------------------------------------------------------------------- + +function createprinterlistwithUNCnames() +{ +if stringinstring help "$@"; then +helpwithcreateprinterlistwithUNCnames ; +else + [ -d ${nthost} ] || mkdir -p ${nthost}; + echo " " + echo " " + echo " " + echo "--> Running now function createprinterlistwithUNCnames()...." + echo "============================================================" + rpcclient -U"${ntprinteradmin}%${ntadminpasswd}" -c 'enumprinters' ${nthost} \ + | grep "description:" \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | sort -f \ + | uniq \ + | tee \ + ${nthost}/printerlistwithUNCnames.txt; + + NUMBEROFPRINTERS=`cat ${nthost}/printerlistwithUNCnames.txt| wc -l`; + echo " "; + echo "--> Finished in running function createprinterlistwithUNCnames...."; + echo "==========================================================================" + echo "NUMBEROFPRINTERS retrieved from \"${nthost}\" is $NUMBEROFPRINTERS".; + echo " --> If you got \"0\" you may want to try again. <---"; + echo "=========================================================================="; + echo " "; + printerlistwithUNCnames=`cat ${nthost}/printerlistwithUNCnames.txt`; +fi +} + + +# ----------------------------------------------------------------------------- +# ----------- Create a list of all printers which have (no) drivers ----------- +# ----------------------------------------------------------------------------- +# + +function helpwithcreatemapofprinterstodrivers() +{ +echo -e " \n\ +################################################################################ +# +# About createmapofprinterdrivers()... +# ------------------------------------ +# +# PRECONDITIONS: 1) This function expects to find a subdirectory '\$nthost' and +# the file '\${nthost}/printerlistwithUNCnames.txt' to exist. +# 2) This functions expects to have the '\$nthosts' variable set +# to an according value. +# +# WHAT IT DOES: This function dissects '\${nthost}/printerlistwithUNCnames.txt' +# and creates some other textfiles from its contents: +# - '\${nthost}/allprinternames.txt' +# - '\${nthost}/alldrivernames.txt' +# - '\${nthost}/allnonrawprinters.txt' +# - '\${nthost}/allrawprinters.txt' +# - '\${nthost}/printertodrivermap.txt' +# and further prints some more info to stdout. +# +# HINT: You currently have defined: 'nthost'=\"$nthost\", which resolves above +# mentioned paths to: +# - '${nthost}/allprinternames.txt' +# - '${nthost}/alldrivernames.txt' +# - '${nthost}/allnonrawprinters.txt' +# - '${nthost}/allrawprinters.txt' +# - '${nthost}/printertodrivermap.txt' +# +################################################################################" +} + +# ----------------------------------------------------------------------------- + +function createmapofprinterstodrivers() +{ +if stringinstring help "$@"; then +helpwithcreatemapofprinterstodrivers ; +else + echo " " + echo " " + echo "--> Running now function createmapofprinterstodrivers()...." + echo "===========================================================" + echo " " + echo " " + echo "ALL PRINTERNAMES:" + echo "=================" + echo " " + cat ${nthost}/printerlistwithUNCnames.txt \ + | awk -F "\\" '{ print $4 }' \ + | awk -F "," '{print $1}' \ + | sort -f \ + | uniq \ + | tee \ + ${nthost}/allprinternames.txt; + + echo " " + echo " " + echo "ALL non-RAW PRINTERS:" + echo "=====================" + echo " " + cat ${nthost}/printerlistwithUNCnames.txt \ + | grep -v ",," \ + | awk -F "\\" '{ print $4 }' \ + | awk -F "," '{print $1}' \ + | sort -f \ + | uniq \ + | tee \ + ${nthost}/allnonrawprinters.txt; + + echo " " + echo " " + echo "ALL RAW PRINTERS:" + echo "================" + echo " " + cat ${nthost}/printerlistwithUNCnames.txt \ + | grep ",," \ + | awk -F "\\" '{ print $4 }' \ + | awk -F "," '{print $1}' \ + | sort -f \ + | uniq \ + | tee \ + ${nthost}/allrawprinters.txt; + + echo " " + echo " " + echo "THE DRIVERNAMES:" + echo "================" + cat ${nthost}/printerlistwithUNCnames.txt \ + | awk -F "," '{print $2 }' \ + | grep -v "^$" \ + | tee \ + ${nthost}/alldrivernames.txt; + + echo " " + echo " " + echo "THE PRINTER-TO-DRIVER-MAP-FOR-non-RAW-PRINTERS:" + echo "===============================================" + cat ${nthost}/printerlistwithUNCnames.txt \ + | awk -F "\\" '{ print $4 }' \ + | awk -F "," '{ print "\"" $1 "\":\"" $2 "\"" }' \ + | grep -v ":\"\"$" \ + | tee \ + ${nthost}/printertodrivermap.txt + echo -e "##########################\n# printer:driver #" >> ${nthost}/printertodrivermap.txt +fi +} + + +# ----------------------------------------------------------------------------- +# ----------- Create a list of all printers which have drivers ---------------- +# ----------------------------------------------------------------------------- +# + +function helpwithgetdrivernamelist() +{ +echo -e " \n\ +################################################################################ +# +# About getdrivernamelist()... +# ---------------------------- +# +# PRECONDITIONS: 1) This function expects to find the subdirectory '\$nthost\' +# otherwise it creates it... +# +# WHAT IT DOES: This function creates the '\${nthost}/printernamelist.txt' +# and also prints it to <stdout>. To do so, it must contact the +# '\$nthost' via rpcclient (which in turn needs '\$ntprinteradmin' +# '\$ntadminpasswd' to log in....). +# +# HINT: The current values: 'nthost'=\"$nthost\" +# 'ntprinteradmin'=\"$ntprinteradmin\" +# 'ntadminpasswd'=<not shown here, check yourself!> +# which resolves above mentioned path to: +# - '${nthost}/printernamelist.txt' +# +################################################################################" +} + +# ----------------------------------------------------------------------------- + +function getdrivernamelist() +{ +if stringinstring help "$@"; then +helpwithgetdrivernamelist ; +else + [ -d ${nthost} ] || mkdir -p ${nthost}; + echo " " + echo " " + echo "--> Running now function getdrivernamelist()...." + echo "================================================" + rpcclient -U${ntprinteradmin}%${ntadminpasswd} -c 'enumprinters' ${nthost} \ + | grep "description:" \ + | grep -v ",," \ + | awk -F "," '{ print $2 }' \ + | sort -f \ + | uniq \ + | tee \ + ${nthost}/drivernamelist.txt +fi +} + + +# ----------------------------------------------------------------------------- +# ----------- Split the driverfile listing between the architectures ---------- +# ----------------------------------------------------------------------------- +# + +function helpwithsplitenumdrivers3list() +{ +echo -e " \n\ +################################################################################ +# +# About splitenumdrivers3list()... +# -------------------------------- +# +# PRECONDITIONS: 1) This function expects write access to the current directory +# and its subdirs '\$nthost/*'. +# 2) This function expects to have the '\$nthost' variable set to +# the according value. +# +# WHAT IT DOES: This function dissects the '\$nthost/enumdrivers3list.txt' +# (using "sed", "cat", "awk" and "grep"). It splits the list up +# into two different files representing a complete list of drivers +# and files for each of the 2 supported architectures. It creates +# '\${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt' +# and '\${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt'. +# +# IF IT DOESN'T WORK: The function "fetchenumdrivers3listfromNThost" may not +# have been run successfully. This is a precondition for +# the current function. +# +# HINT: You currently have defined: 'nthost'=\"$nthost\", which resolves above +# mentioned paths to: +# - '${nthost}/WIN40/${nthost}-enumdrivers3list-NTx86.txt' +# - '${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt' +# +################################################################################" +} + +# ----------------------------------------------------------------------------- + +function splitenumdrivers3list() +{ +if stringinstring help "$@"; then +helpwithsplitenumdrivers3list ; +else + echo " " + echo " " + echo "--> Running now function splitenumdrivers3list()...." + echo "====================================================" + + [ -d ${nthost}/WIN40 ] || mkdir -p ${nthost}/WIN40; + [ -d ${nthost}/W32X86 ] || mkdir -p ${nthost}/W32X86; + + cat ${nthost}/enumdrivers3list.txt \ + | sed -e '/^\[Windows NT x86\]/,$ d' \ + | tee \ + ${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt ; + + cat ${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt \ + | grep Version \ + | sort -f \ + | uniq \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | tee ${nthost}/WIN40/availableversionsWIN40.txt ; + +# cd ${nthost}/WIN40/ ; +# mkdir $( cat availableversionsWIN40.txt ) 2> /dev/null ; +# cd - ; + + cat ${nthost}/enumdrivers3list.txt \ + | sed -e '/^\[Windows NT x86\]/,$! d' \ + | tee \ + ${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt ; + + cat ${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt \ + | grep Version \ + | sort -f \ + | uniq \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | tee ${nthost}/W32X86/availableversionsW32X86.txt ; + +# cd ${nthost}/W32X86/ ; +# mkdir $( cat availableversionsW32X86.txt ) 2> /dev/null ; +# cd - ; +fi +} + + +# ----------------------------------------------------------------------------- +# ---------- Make subdirs in ./${sambahost}/WIN40/ for each driver.... ------- +# ----------------------------------------------------------------------------- +# + +function helpwithmakesubdirsforWIN40driverlist() +{ +echo -e " \n\ +################################################################################ +# +# About makesubdirsforWIN40driverlist() and makesubdirsforWIN40driverlist ()... +# ----------------------------------------------------------------------------- +# +# PRECONDITIONS: 1) These functions expect write access to the current directory +# 2) These functions expect to have the '\$nthost' variable set +# to the according value. +# 3) These functions expect to find the two files +# '\${nthost}/WIN40/\${nthost}-enumdrivers3list-WIN40.txt' and +# '\${nthost}/W32X86/\${nthost}-enumdrivers3list-NTx86.txt' to +# work on. +# +# WHAT IT DOES: These functions dissect the '$nthost/enumdrivers3list.txt' +# (using "sed", "cat", "awk" and "grep"). They split the input +# files up into individual files representing driver(version)s and +# create appropriate subdirectories for each driver and version +# underneath './\$nthost/<architecture>'. They use the drivernames +# (including spaces) for the directory names. ("/" -- slashes -- +# in drivernames are converted to underscores). +# +# IF IT DOESN'T WORK: The function "fetchenumdrivers3listfromNThost" and +# consecutive ones may not have been run successfully. This +# is a precondition for the current function. +# +# HINT: You currently have defined: 'nthost'=\"$nthost\", which resolves above +# mentioned paths to: +# - '\${nthost}/WIN40/\${nthost}-enumdrivers3list-NTx86.txt' +# - '\${nthost}/W32X86/\${nthost}-enumdrivers3list-NTx86.txt' +# +################################################################################ +# ............PRESS \"q\" TO QUIT............" \ +|less +} + +# ----------------------------------------------------------------------------- + +function makesubdirsforWIN40driverlist() +{ +if stringinstring help "$@"; then +helpwithmakesubdirsforWIN40driverlist ; +else + cat ${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt \ + | grep "Driver Name:" \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | sort -f \ + | uniq \ + | tr / _ \ + | sed -e 's/$/\"/' \ + | sed -e 's/^/mkdir -p '"\"${nthost}"'\/WIN40\//' \ + | tee \ + ${nthost}/makesubdirsforWIN40driverlist.txt; + + sh -x ${nthost}/makesubdirsforWIN40driverlist.txt; + +# rm ${nthost}/makesubdirsforWIN40driverlist.txt; +fi +} + + +# ----------------------------------------------------------------------------- +# ---------- Make subdirs in ./${sambahost}/W32X86/ for each driver.... ------- +# ----------------------------------------------------------------------------- +# + +function makesubdirsforW32X86driverlist() +{ +if stringinstring help "$@"; then +helpwithvampiredrivers ; +else + cat ${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt \ + | grep "Driver Name:" \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | sort -f \ + | uniq \ + | tr / _ \ + | sed -e 's/$/\"/' \ + | sed -e 's/^ */mkdir '\""${nthost}"'\/W32X86\//' \ + | tee \ + ${nthost}/makesubdirsforW32X86driverlist.txt; + + sh -x ${nthost}/makesubdirsforW32X86driverlist.txt; + +# rm ${nthost}/makesubdirsforW32X86driverlist.txt; +fi +} + + + + +# ----------------------------------------------------------------------------- +# ----------- Split the WIN40 driverfile listing of each architecture --------- +# ------------------------ into individual drivers ---------------------------- +# ----------------------------------------------------------------------------- +# + +function helpwithmakesubdirsforWIN40driverlist() +{ +echo -e " \n\ +################################################################################ +# +# About splitWIN40fileintoindividualdriverfiles() and +# splitW32X86fileintoindividualdriverfiles()... +# --------------------------------------------------- +# +# PRECONDITIONS: 1) These functions expect write access to the current directory +# and its subdirs '\$nthost/*/'. +# 2) These functions expect to have the '\$nthost' variable set +# to the according value. +# 3) These functions expect to find the two files +# '\${nthost}/WIN40/\${nthost}-enumdrivers3list-WIN40.txt' and +# '\${nthost}/W32X86/\${nthost}-enumdrivers3list-NTx86.txt' to +# work on. +# +# WHAT IT DOES: 1) These functions create a directory for each printer driver. +# The directory name is identical to the driver name. +# 2) For each supported driver version (\"0\", \"2\" and \"3\") it +# creates a subdirectory as required underneath +# './\$nthost/<architecture>'. +# 3) The directories use the drivernames (including spaces) for +# their names. ("/" - slashes - in drivernames are converted to +# underscores). +# 4) In each subdirectory they dissect the original +# '\$nthost/enumdrivers3list.txt' (using "sed", "cat", "awk" +# and "grep") and store that part describing the related driver +# (under the name \"driverfilesversion.txt\". +# 5) For each driver the files \"Drivername\", \"DriverPath\", +# \"Drivername\", \"Configfile\", \"Helpfile\", \"AllFiles\" and +# \"Dependentfilelist\" are stored in the according directory +# which hold contend that is used by other (downstream) +# functions. +# 6) It creates a file named \"AllFilesIAskFor\" which holds the +# case sensitive names of files it wanted to download. It also +# creates a file named \"AllFilesIGot\" which holds the case +# sensitive spelling of the downloaded files. (Due to +# Microsoft's ingenious file naming tradition, you may have +# asked for a \"PS5UI.DLL\" but gotten a \"ps5ui.dll\". +# 7) The 2 files from 6) will be later compared with the help of +# the \"sdiff\" utility to decide how to re-name the files so +# that the subsequent driver upload command's spelling +# convention is met. +# +# IF IT DOESN'T WORK: The function \"fetchenumdrivers3listfromNThost\" and +# consecutive ones may not have been run successfully. This +# is a precondition for the current function. +# +# HINT: You currently have defined: 'nthost'=\"$nthost\". +# +################################################################################ +# ............PRESS \"q\" TO QUIT............" \ +|less +} + +# ----------------------------------------------------------------------------- + +function splitWIN40fileintoindividualdriverfiles() +{ +if stringinstring help "$@"; then +helpwithmakesubdirsforWIN40driverlist ; +else + echo " " + echo " " + echo "--> Running now function splitWIN40fileintoindividualdriverfiles()..." + echo "=====================================================================" + + for i in ${nthost}/WIN40/*/; do + CWD1="$( pwd )" ; + cd "${i}" ; + echo " " + echo " " + echo " ###########################################################################################" + echo " " + echo " Next driver is \"$( basename "$( pwd)" )\"" + echo " " + echo " ###########################################################################################" + +##### echo "yes" | cp -f ../../../${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt . 2> /dev/null ; + ln -s -f ../${nthost}-enumdrivers3list-WIN40.txt ${nthost}-enumdrivers3list-WIN40.lnk ; + + tac ${nthost}-enumdrivers3list-WIN40.lnk \ + | sed -e '/'"$(basename "$(echo "$PWD")")"'/,/Version/ p' -n \ + | grep Version \ + | uniq \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print "mkdir \"" $1 "\"" }' \ + | tee mkversiondir.txt ; + + sh mkversiondir.txt 2> /dev/null ; + + cat ${nthost}-enumdrivers3list-WIN40.lnk \ + | sed -e '/\['"$(basename "$(echo "$PWD")")"'\]/,/Monitor/ w alldriverfiles.txt' -n ; + + for i in */; do + CWD2="$( pwd )" ; + cd "${i}"; + echo "yes" | cp ../alldriverfiles.txt . 2> /dev/null ; + + cat alldriverfiles.txt \ + | egrep '(\\'"$(basename "$( pwd )")"'\\|Driver Name)' \ + | tee driverfilesversion.txt ; + + Drivername=$( grep "Driver Name:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | sort -f \ + | uniq \ + | tee Drivername ) ; + + DriverPath=$( grep "Driver Path:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "WIN40" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + echo "${DriverPath}" \ + | tee DriverPath ; + + Datafile=$( grep "Datafile:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "WIN40" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + echo "${Datafile}" \ + | tee Datafile ; + + Configfile=$( grep "Configfile:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "WIN40" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + echo "${Configfile}" \ + | tee Configfile ; + + Helpfile=$( grep "Helpfile:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "WIN40" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + echo "${Helpfile}" \ + | tee Helpfile ; + + Dependentfilelist=$( grep "Dependentfiles:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "WIN40" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + + Dependentfiles=$( echo $Dependentfilelist \ + | sed -e 's/ /,/g ' ) ; + + echo "${Dependentfiles}" \ + | tee Dependentfiles + + AllFiles=$( echo ${Dependentfilelist}; echo ${Helpfile}; echo ${Configfile}; echo ${Datafile}; echo ${DriverPath} ); + + echo "${AllFiles}" \ + | sort -f \ + | uniq \ + | tee AllFiles ; + + for i in $( cat AllFiles ); do echo ${i}; done \ + | sort -f \ + | uniq \ + | tee AllFilesIAskFor ; + + cd "${CWD2}" 1> /dev/null ; + done + +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "adddriver \"${Architecture}\" \"${DriverName}:${DriverPath}:${Datafile}:${Configfile}:${Helpfile}:NULL:RAW:${Dependentfiles}\" ${Version}" \ ${smbhost} + +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "setdriver \"${printername}\" \"${DriverName}\"" \ +# ${smbhost} +# +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "setprinter \"${printername}\" \"Driver was installed and set via MS-RPC (utilized by Kurt Pfeifle\'s set of \"Vampire Printerdrivers\" scripts from Linux)\"" \ +# ${smbhost} + + cd "${CWD1}" 1> /dev/null ; + done; +fi +} + + + + +# ----------------------------------------------------------------------------- +# ---------- Split the W32X86 driverfile listing of each architecture --------- +# ------------------------ into individual drivers ---------------------------- +# ----------------------------------------------------------------------------- +# + +function splitW32X86fileintoindividualdriverfiles() +{ +if stringinstring help "$@"; then +helpwithmakesubdirsforWIN40driverlist ; +else + echo " " + echo " " + echo "--> Running now function splitW32X86fileintoindividualdriverfiles()..." + echo "======================================================================" + + for i in ${nthost}/W32X86/*/; do + CWD1="$( pwd )" ; + cd "${i}" ; + echo " " + echo " " + echo " ###########################################################################################" + echo " " + echo " Next driver is \"$( basename "$( pwd)" )\"" + echo " " + echo " ###########################################################################################" + +###### echo "yes" | cp -f ../../../${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt . 2> /dev/null ; + ln -s -f ../${nthost}-enumdrivers3list-NTx86.txt ${nthost}-enumdrivers3list-NTx86.lnk ; + + tac ${nthost}-enumdrivers3list-NTx86.lnk \ + | sed -e '/'"$(basename "$(echo "$PWD")")"'/,/Version/ p' -n \ + | grep Version \ + | uniq \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print "mkdir \"" $1 "\"" }' \ + | tee mkversiondir.txt ; + + sh mkversiondir.txt 2> /dev/null ; + + cat ${nthost}-enumdrivers3list-NTx86.lnk \ + | sed -e '/\['"$(basename "$(echo "$PWD")")"'\]/,/Monitor/ w alldriverfiles.txt' -n ; + + for i in */; do + CWD2="$( pwd )" ; + cd "${i}"; + echo "yes" | cp ../alldriverfiles.txt . 2> /dev/null ; + + cat alldriverfiles.txt \ + | egrep '(\\'"$(basename "$( pwd )")"'\\|Driver Name)' \ + | tee driverfilesversion.txt ; + + Drivername=$( grep "Driver Name:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | sort -f \ + | uniq \ + | tee Drivername ) ; +# echo "${Drivername}" \ +# | tee Drivername ; + + + DriverPath=$( grep "Driver Path:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "W32X86" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + echo "${DriverPath}" \ + | tee DriverPath ; + + Datafile=$( grep "Datafile:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "W32X86" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + echo "${Datafile}" \ + | tee Datafile ; + + Configfile=$( grep "Configfile:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "W32X86" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + echo "${Configfile}" \ + | tee Configfile ; + + Helpfile=$( grep "Helpfile:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "W32X86" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + echo "${Helpfile}" \ + | tee Helpfile ; + + Dependentfilelist=$( grep "Dependentfiles:" driverfilesversion.txt \ + | awk -F "[" '{ print $2 }' \ + | awk -F "]" '{ print $1 }' \ + | awk -F "W32X86" '{ print $2 }' \ + | awk -F "\\" '{ print $3 }' \ + | sort -f \ + | uniq ) ; + + Dependentfiles=$( echo $Dependentfilelist \ + | sed -e 's/ /,/g ' ) ; + + echo "${Dependentfiles}" \ + | tee Dependentfiles + + AllFiles=$( echo ${Dependentfilelist}; echo ${Helpfile}; echo ${Configfile}; echo ${Datafile}; echo ${DriverPath} ) ; + + echo "${AllFiles}" \ + | sort -f \ + | uniq \ + | tee AllFiles ; + + for i in $( cat AllFiles ); do echo ${i}; done \ + | sort -f \ + | uniq \ + | tee AllFilesIAskFor ; + + cd "${CWD2}" 1> /dev/null ; + done + +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "adddriver \"${Architecture}\" \"${DriverName}:${DriverPath}:${Datafile}:${Configfile}:${Helpfile}:NULL:RAW:${Dependentfiles}\" ${Version}" \ ${smbhost} + +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "setdriver \"${printername}\" \"${DriverName}\"" \ +# ${smbhost} +# +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "setprinter \"${printername}\" \"Driver was installed and set via MS-RPC (utilized by Kurt Pfeifle\'s set of \"Vampire Printerdrivers\" scripts from Linux)\"" \ +# ${smbhost} + + cd "${CWD1}" 1> /dev/null ; + done; +fi +} + + + +# ----------------------------------------------------------------------------- +# ------------------ First download the driverfiles........... ---------------- +# ----------------------------------------------------------------------------- +# + +function helpwithfetchallW32X86driverfiles() +{ +echo -e " \n\ +################################################################################ +# +# About fetchallW32X86driverfiles()... +# ------------------------------------ +# +# PRECONDITIONS: 1) This function expects to have the \'\$nthost\' variable set +# to the according value. +# 2) This function expects to find files \"AllFiles\", +# \"AllFilesIAskFor\", and \"AllFilesIGot\" in the directories +# \'\${nthost}/<architecture>/<drivername>/<version>/\'. +# +# WHAT IT DOES: These functions use \"smbclient\" to connect to the NT print +# server \"\$nthost\" and download the printer driver files from +# there. To achieve that in an orderly fashion, the previously +# created subdirectories (named like the drivers to fetch) are +# visited in turn and the related files are downloaded for each +# driver/directory. +# +# IF IT DOESN'T WORK: The function \"fetchenumdrivers3listfromNThost\" and +# consecutive ones may not have been run successfully. This +# is a precondition for the current function. +# +# HINT: The current values: 'nthost'=\"$nthost\" +# 'ntprinteradmin'=\"$ntprinteradmin\" +# 'ntadminpasswd'=<not shown here, check yourself!> +# +################################################################################" +} + +# ----------------------------------------------------------------------------- + +function fetchallW32X86driverfiles() +{ +if stringinstring help "$@"; then +helpwithfetchallW32X86driverfiles ; +else + echo " " + echo " " + echo "--> Running now function fetchallW32X86driverfiles()...." + echo "========================================================" + + CURRENTWD=${PWD} ; + for i in ${nthost}/W32X86/*/*/ ; do \ + cd "${i}"; + + driverversion="$(basename "$(echo "$PWD")")" ; + echo "$(basename "$(echo "$PWD")")" > driverversion ; + + AllFiles=$( cat AllFiles ) ; + + [ -d TheFiles ] || mkdir TheFiles; + + cd TheFiles; + + echo " " + echo "====================================================" + echo "Downloading files now to ${PWD}...."; + echo "====================================================" + echo " " + + # Fetch the Driver files from the Windoze box (printserver) + smbclient -U"${ntprinteradmin}%${ntadminpasswd}" -d 2 \ + //${nthost}/print\$ -c \ + "cd W32X86\\${driverversion};prompt;mget ${AllFiles}" + + ls -1 \ + | sort -f \ + | uniq \ + | tee ../AllFilesIGot ; + + cd ${CURRENTWD} ; + + done ; +fi +} + + +# ----------------------------------------------------------------------------- +# -------------- Now upload the driverfiles and activate them! ---------------- +# Upload files into root "Architecture" directory of Samba'a [print$] share... +# ----------------------------------------------------------------------------- +# + +function helpwithuploadallW32X86drivers() +{ +echo -e " \n\ +################################################################################ +# +# About uploadallW32X86drivers()... +# --------------------------------- +# +# PRECONDITIONS: 1) This function expects to have the '\$nthost', +# '\$ntprinteradmin' and '\$ntadminpasswd' variables set to +# according values. +# 2) This function expects to find the files \"AllFiles\", +# \"AllFilesIGot\" and \"AllFilesIAskFor\" in the +# \"\${nthost}/W32X86<drivername>/<driverversion>/TheFiles\" +# subdirectory. +# +# WHAT IT DOES: This function uses "smbclient" to connect to the new Samba print +# server "\$nthost" and upload the printer driver files into the +# \"[print\$]\" share there. To achieve that in orderly fashion, +# the previously created subdirectories (named like the drivers +# fetched previously from \$smbhost) are visited in turn and the +# related files are uploaded for each driver/directory. For this +# to really succeed, the files \"AllFilesIGot\" and \"AllFilesIAskFor\" +# are compared with the help of the \"sdiff\" utility to decide +# how to re-name the mis-matching filenams, so that the used +# driver upload command's spelling convention is met.... +# +# IF IT DOESN'T WORK: The function "fetchenumdrivers3listfromNThost" and +# consecutive ones may not have been run successfully. This +# is a precondition for the current function. +# +# HINT: The current values: 'nthost'=\"$nthost\" +# 'ntprinteradmin'=\"$ntprinteradmin\" +# 'ntadminpasswd'=<not shown here, check yourself!> +# +################################################################################ +# ............PRESS \"q\" TO QUIT............" \ +|less +} + +# ----------------------------------------------------------------------------- + +function uploadallW32X86drivers() +{ +if stringinstring help "$@"; then +helpwithuploadallW32X86drivers ; +else + echo " " + echo " " + echo "--> Running now function uploadallW32X86drivers()...." + echo "=====================================================" + + for i in ${nthost}/W32X86/*/*/; do \ + CURRENTWD=${PWD} ; + cd "${i}" ; + # we are now in [..]/W32X86/[drvrname]/[2|3]/ + + driverversion="$(basename "$(echo "$PWD")")" ; + + echo "$(basename "$(echo "$PWD")")" > driverversion ; + + cd TheFiles ; + # we are now in [..]/W32X86/[drvrname]/[2|3]/TheFiles + echo " " + echo "====================================================" + echo "Uploading driverfiles now from ${PWD}...."; + echo "====================================================" + echo " " + set -x ; + + smbclient -U"${smbprinteradmin}%${smbadminpasswd}" -d 2 \ + //${smbhost}/print\$ \ + -c "mkdir W32X86;cd W32X86;prompt;mput $( cat ../AllFilesIGot )"; + + cd .. ; + # we are now in [..]/W32X86/[drvrname]/[2|3]/ + +# Now tell Samba that those files are *printerdriver* files.... +# The "adddriver" command will move them to the "0" subdir and create or +# update the associated *.tdb files (faking the MS Windows Registry on Samba) + Drivername="$( cat Drivername )" + + set -x ; + [ x"$( cat Dependentfiles)" == x"" ] && echo NULL > Dependentfiles; + + sdiff -s AllFilesIGot AllFilesIAskFor \ + | tee sdiff-of-Requested-and-Received.txt ; + + [ -s sdiff-of-Requested-and-Received.txt ] \ + || rm -f sdiff-of-Requested-and-Received.txt \ + && cat sdiff-of-Requested-and-Received.txt > ../sdiff-of-Requested-and-Received.txt ; + + cat sdiff-of-Requested-and-Received.txt \ + | sed -e 's/^/mv /' \ + | sed -e 's/ *|/ /' \ + | tee rename-Received-to-Requested-case.txt ; + + sh -x rename-Received-to-Requested-case.txt ; + + mv rename-Received-to-Requested-case.txt rename-Received-to-Requested-case.done ; + + echo " ################ B E G I N DEBUGGING STATEMENT ############" + echo "rpcclient -U\"${smbprinteradmin}%${smbadminpasswd}\" -d 2 \ + -c \'adddriver \"Windows NT x86\" \"$( cat Drivername ):$( cat DriverPath ):$( cat Datafile ):$( cat Configfile ):$( cat Helpfile ):NULL:RAW:$( cat Dependentfiles )\" $( cat driverversion )" \ + ${smbhost} \' ; + echo " ################ E N D DEBUGGING STATEMENT ################" + + rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" -d 2 \ + -c "adddriver \"Windows NT x86\" \"$( cat Drivername ):$( cat DriverPath ):$( cat Datafile ):$( cat Configfile ):$( cat Helpfile ):NULL:RAW:$( cat Dependentfiles )\" $( cat driverversion )" \ + ${smbhost} ; + + set +x ; + + cd ${CURRENTWD} ; + # we are now back to where we started + done; + set +x ; +fi +} + +# Now tell Samba which printqueue this driver is associated with.... +# The "setdriver" command will do just that and create or +# update the associated *.tdb files (faking the MS Windows Registry on Samba) +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "setdriver \"${printername}\" \"${DriverName}\"" \ +# ${smbhost} +# -- NOT YET IMPLEMENTED IN THIS SCRIPT --- +# + +# Now set a nice printer comment and let the world know what we've done +# (or not.... ;-) +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "setprinter \"${printername}\" \"Driver was installed and set via MS-RPC (rpcclient commandline from Linux)\"" \ +# ${smbhost} +# -- NOT YET IMPLEMENTED IN THIS SCRIPT --- +# + + +# ----------------------------------------------------------------------------- +# ------------------ First download the driverfiles........... ---------------- +# ----------------------------------------------------------------------------- +# + +function helpwithfetchallWIN40driverfiles() +{ +echo -e " \n\ +################################################################################ +# +# About fetchallWIN40driverfiles()... +# ----------------------------------- +# +# PRECONDITIONS: 1) This function expects to have the \$nthost variable set to +# the according value. +# 2) This function expects to find the \"AllFiles\" file in +# \"\${nthost}/WIN40<drivername>/<driverversion>/TheFiles\". +# +# WHAT IT DOES: These functions use "smbclient" to connect to the NT print server +# "\$nthost" and download the printer driver files from there. To +# achieve that in an orderly fashion, the previously created +# subdirectories (named like the drivers to fetch) are visited in +# turn and the related files are downloaded for each +# driver/directory. +# +# IF IT DOESN'T WORK: The function "fetchenumdrivers3listfromNThost" and +# consecutive ones may not have been run successfully. This +# is a precondition for the current function. +# +# HINT: The current values: 'nthost'=\"$nthost\" +# 'ntprinteradmin'=\"$ntprinteradmin\" +# 'ntadminpasswd'=<not shown here, check yourself!> +# +################################################################################ +# ............PRESS \"q\" TO QUIT............" \ +|less +} + +# ----------------------------------------------------------------------------- + +function fetchallWIN40driverfiles() +{ +if stringinstring help "$@"; then +helpwithfetchallWIN40driverfiles ; +else + echo " " + echo " " + echo "--> Running now function fetchallWIN40driverfiles()...." + echo "=======================================================" + + CURRENTWD=${PWD} ; + + for i in ${nthost}/WIN40/*/*/; do \ + cd "${i}"; + + driverversion="$(basename "$(echo "$PWD")")" ; + echo "$(basename "$(echo "$PWD")")" > driverversion ; + + AllFiles=$( cat AllFiles ) ; + + [ -d TheFiles ] || mkdir TheFiles; + + cd TheFiles; + + echo " " + echo "====================================================" + echo "Downloading files now to ${PWD}...."; + echo "====================================================" + echo " " + + # Fetch the Driver files from the Windoze box (printserver) + smbclient -U"${ntprinteradmin}%${ntadminpasswd}" -d 2 \ + //${nthost}/print\$ -c \ + "cd WIN40\\${driverversion};prompt;mget ${AllFiles}" ; + + ls -1 \ + | sort -f \ + | uniq \ + | tee ../AllFilesIGot ; + + cd ${CURRENTWD} ; + + done ; +fi +} + + +# ----------------------------------------------------------------------------- +# -------------- Now upload the driverfiles and activate them! ---------------- +# Upload files into root "Architecture" directory of Samba'a [print$] share... +# ----------------------------------------------------------------------------- +# + +function helpwithuploadallWIN40drivers() +{ +echo -e " \n\ +################################################################################ +# +# About uploadallWIN40drivers()... +# -------------------------------- +# +# PRECONDITIONS: 1) This function expects to have '\$smbhost', '\$smbprinteradmin' +# and '\$smbadminpasswd' variables set to according values. +# 2) This function expects to find \"AllFiles\", \"AllFilesIGot\" +# and \"AllFilesIAskFor\" in the subdirectory +# \"\${nthost}/WINI40/<drivername>/<driverversion>/TheFiles\". +# +# WHAT IT DOES: These function uses \"smbclient\" to connect to the new Samba +# print server "\$nthost" and upload the printer driver files into +# the \"[print\$]\" share there. +# To achieve that in an orderly fashion, the previously created +# subdirectories (named like the drivers fetched previously from +# \$smbhost) are visited in turn and the related files are +# uploaded for each driver/directory. +# For this to really succeed, \"AllFilesIGot\" and \"AllFilesIAskFor\" +# are compared with the help of the \"sdiff\" utility to decide +# how to re-name the mis-matching filenams, so that the used +# driver upload command's spelling convention is met.... +# +# IF IT DOESN'T WORK: The function \"fetchenumdrivers3listfromNThost\" and +# consecutive ones may not have been run successfully. This +# is a precondition for the current function. +# +# HINT: The current values: 'nthost'=\"$nthost\" +# 'ntprinteradmin'=\"$ntprinteradmin\" +# 'ntadminpasswd'=<not shown here, check yourself!> +# +################################################################################ +# ............PRESS \"q\" TO QUIT............" \ +|less +} +function uploadallWIN40drivers() +{ +if stringinstring help "$@"; then +helpwithuploadallWIN40drivers ; +else + echo " " + echo " " + echo "--> Running now function uploadallWIN40drivers()...." + echo "====================================================" + + for i in ${nthost}/WIN40/*/*/; do \ + CURRENTWD=${PWD} ; + cd "${i}" ; + # we are now in [..]/WIN40/[drvrname]/[0]/ + + driverversion="$(basename "$(echo "$PWD")")" ; + + echo "$(basename "$(echo "$PWD")")" > driverversion ; + + cd TheFiles ; + # we are now in [..]/WIN40/[drvrname]/[0]/TheFiles + echo " " + echo "====================================================" + echo "Uploading driverfiles now from ${PWD}...."; + echo "====================================================" + echo " " + set -x ; + + smbclient -U"${smbprinteradmin}%${smbadminpasswd}" -d 2 \ + //${smbhost}/print\$ \ + -c "mkdir WIN40;cd WIN40;prompt;mput $( cat ../AllFilesIGot )"; + + cd .. ; + # we are now in [..]/WIN40/[drvrname]/[0]/ + +# Now tell Samba that those files are *printerdriver* files.... +# The "adddriver" command will move them to the "0" subdir and create or +# update the associated *.tdb files (faking the MS Windows Registry on Samba) + Drivername="$( cat Drivername )" + + set -x ; + [ x"$( cat Dependentfiles)" == x"" ] && echo NULL > Dependentfiles; + + sdiff -s AllFilesIGot AllFilesIAskFor \ + | tee sdiff-of-Requested-and-Received.txt ; + + [ -s sdiff-of-Requested-and-Received.txt ] \ + || rm -f sdiff-of-Requested-and-Received.txt \ + && cat sdiff-of-Requested-and-Received.txt > ../sdiff-of-Requested-and-Received.txt ; + + cat sdiff-of-Requested-and-Received.txt \ + | sed -e 's/^/mv /' \ + | sed -e 's/ *|/ /' \ + | tee rename-Received-to-Requested-case.txt ; + + sh -x rename-Received-to-Requested-case.txt ; + + mv rename-Received-to-Requested-case.txt rename-Received-to-Requested-case.done ; + + echo " ################ DEBUGGING STATEMENT " + echo "rpcclient -U\"${smbprinteradmin}%${smbadminpasswd}\" -d 2 \ + -c \'adddriver \"Windows NT x86\" \"$( cat Drivername ):$( cat DriverPath ):$( cat Datafile ):$( cat Configfile ):$( cat Helpfile ):NULL:RAW:$( cat Dependentfiles )\" $( cat driverversion )" \ + ${smbhost}\' ; + echo " ################ DEBUGGING STATEMENT " + + rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" -d 2 \ + -c "adddriver \"Windows 4.0\" \"$( cat Drivername ):$( cat DriverPath ):$( cat Datafile ):$( cat Configfile ):$( cat Helpfile ):NULL:RAW:$( cat Dependentfiles )\" $( cat driverversion )" \ + ${smbhost} ; + + set +x ; + cd ${CURRENTWD} ; + # we are now back to where we started + done; +fi +} + +# Now tell Samba which printqueue this driver is associated with.... +# The "setdriver" command will do just that and create or +# update the associated *.tdb files (faking the MS Windows Registry on Samba) +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "setdriver \"${printername}\" \"${DriverName}\"" \ +# ${smbhost} +# -- NOT YET IMPLEMENTED IN THIS SCRIPT --- +# +# Now set a nice printer comment and let the world know what we've done +# (or not.... ;-) +# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \ +# -c "setprinter \"${printername}\" \"Driver was installed and set via MS-RPC (rpcclient commandline from Linux)\"" \ +# ${smbhost} +# -- NOT YET IMPLEMENTED IN THIS SCRIPT --- +# + + +#source ${0} ; + +enumallfunctions; diff --git a/examples/printing/prtpub.c b/examples/printing/prtpub.c new file mode 100644 index 0000000..2839940 --- /dev/null +++ b/examples/printing/prtpub.c @@ -0,0 +1,237 @@ +/* + * Set printer capabilities in DsDriver Keys on remote printer + * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* This needs to be defined for certain compilers */ +#define WINVER 0x0500 + +#include <tchar.h> +#include <windows.h> +#include <stdio.h> + +#define SAMBA_PORT _T("Samba") + +TCHAR *PrintLastError(void) +{ + static TCHAR msgtxt[1024*sizeof(TCHAR)]; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), + 0, msgtxt, 0, NULL); + + return msgtxt; +} + +void map_orientation(HANDLE ph, TCHAR *printer, TCHAR *port) +{ + DWORD rot; + TCHAR portrait_only[] = _T("PORTRAIT\0"); + TCHAR both[] = _T("LANDSCAPE\0PORTRAIT\0"); + + /* orentation of 90 or 270 indicates landscape supported, 0 means it isn't */ + rot = DeviceCapabilities(printer, port, DC_BINNAMES, NULL, NULL); + + printf("printOrientationsSupported:\n"); + + if (rot) { + printf("\tPORTRAIT\n\tLANDSCAPE\n"); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printOrientationsSupported"), REG_MULTI_SZ, + both, sizeof(both)); + } else { + printf("\tPORTRAIT\n"); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printOrientationsSupported"), REG_MULTI_SZ, + portrait_only, sizeof(portrait_only)); + } +} + +void map_resolution(HANDLE ph, TCHAR *printer, TCHAR *port) +{ + DWORD num, *res, maxres = 0, i; + + num = DeviceCapabilities(printer, port, DC_ENUMRESOLUTIONS, NULL, NULL); + if ((DWORD) -1 == num) + return; + res = malloc(num*2*sizeof(DWORD)); + num = DeviceCapabilities(printer, port, DC_ENUMRESOLUTIONS, (BYTE *) res, NULL); + for (i=0; i < num*2; i++) { + maxres = (res[i] > maxres) ? res[i] : maxres; + } + printf("printMaxResolutionSupported: %d\n", maxres); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMaxResolutionSupported"), REG_DWORD, + (BYTE *) &maxres, sizeof(maxres)); +} + +void map_extents(HANDLE ph, TCHAR *printer, TCHAR *port) +{ + DWORD extentval, xval, yval; + + extentval = DeviceCapabilities(printer, port, DC_MINEXTENT, NULL, NULL); + xval = (DWORD) (LOWORD(extentval)); + yval = (DWORD) (HIWORD(extentval)); + printf("printMinXExtent: %d\n", xval); + printf("printMinYExtent: %d\n", yval); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMinXExtent"), REG_DWORD, (BYTE *) &xval, sizeof(xval)); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMinYExtent"), REG_DWORD, (BYTE *) &yval, sizeof(yval)); + extentval = DeviceCapabilities(printer, port, DC_MAXEXTENT, NULL, NULL); + xval = (DWORD) (LOWORD(extentval)); + yval = (DWORD) (HIWORD(extentval)); + printf("printMaxXExtent: %d\n", xval); + printf("printMaxYExtent: %d\n", yval); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMaxXExtent"), REG_DWORD, (BYTE *) &xval, sizeof(xval)); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMaxYExtent"), REG_DWORD, (BYTE *) &yval, sizeof(yval)); +} + +void map_printrateunit(HANDLE ph, TCHAR *printer, TCHAR *port) +{ + DWORD unit; + TCHAR ppm[] = _T("PagesPerMinute"); + TCHAR ipm[] = _T("InchesPerMinute"); + TCHAR lpm[] = _T("LinesPerMinute"); + TCHAR cps[] = _T("CharactersPerSecond"); + + unit = DeviceCapabilities(printer, port, DC_PRINTRATEUNIT, NULL, NULL); + switch(unit) { + case PRINTRATEUNIT_PPM: + printf("printRateUnit: %s\n", ppm); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printRateUnit"), REG_SZ, ppm, sizeof(ppm)); + break; + case PRINTRATEUNIT_IPM: + printf("printRateUnit: %s\n", ipm); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printRateUnit"), REG_SZ, ipm, sizeof(ipm)); + break; + case PRINTRATEUNIT_LPM: + printf("printRateUnit: %s\n", lpm); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printRateUnit"), REG_SZ, lpm, sizeof(lpm)); + break; + case PRINTRATEUNIT_CPS: + printf("printRateUnit: %s\n", cps); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printRateUnit"), REG_SZ, cps, sizeof(cps)); + break; + default: + printf("printRateUnit: unknown value %d\n", unit); + } +} + +void map_generic_boolean(HANDLE ph, TCHAR *printer, TCHAR *port, WORD cap, TCHAR *key) +{ + BYTE boolval; + /* DeviceCapabilities doesn't always return 1 for true...just nonzero */ + boolval = (BYTE) (DeviceCapabilities(printer, port, cap, NULL, NULL) ? 1 : 0); + printf("%s: %s\n", key, boolval ? "TRUE" : "FALSE"); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, key, REG_BINARY, &boolval, sizeof(boolval)); +} + +void map_generic_dword(HANDLE ph, TCHAR *printer, TCHAR *port, WORD cap, TCHAR *key) +{ + DWORD dword; + + dword = DeviceCapabilities(printer, port, cap, NULL, NULL); + if ((DWORD) -1 == dword) + return; + + printf("%s: %d\n", key, dword); + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, key, REG_DWORD, (BYTE *) &dword, sizeof(dword)); +} + +void map_generic_multi_sz(HANDLE ph, TCHAR *printer, TCHAR *port, WORD cap, TCHAR *key, int size) +{ + TCHAR *strings_in; + TCHAR *strings_out, *strings_cur; + DWORD num_items, i; + + num_items = DeviceCapabilities(printer, port, cap, NULL, NULL); + if ((DWORD) -1 == num_items) + return; + strings_in = malloc(num_items * size); + strings_out = calloc(num_items, size); + num_items = DeviceCapabilities(printer, port, cap, strings_in, NULL); + printf("%s:\n", key); + for (i=0, strings_cur = strings_out; i < num_items; i++) { + _tcsncpy(strings_cur, &strings_in[i*size], size); + printf("\t%s\n", strings_cur); + strings_cur += _tcslen(strings_cur) + 1; + } + + SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, key, REG_MULTI_SZ, strings_out, + (strings_cur - strings_out + 1) * sizeof(TCHAR)); + + free(strings_in); + free(strings_out); +} + +int main(int argc, char *argv[]) +{ + HANDLE ph; + BYTE *driver_info; + DWORD needed; + TCHAR *printer; + TCHAR *port = SAMBA_PORT; + PRINTER_DEFAULTS admin_access = {NULL, NULL, PRINTER_ACCESS_ADMINISTER}; + PRINTER_INFO_7 publish = {NULL, DSPRINT_PUBLISH}; + + if (argc < 2) { + printf("Usage: %s <printername>\n", argv[0]); + return -1; + } + + printer = argv[1]; + + if (!(OpenPrinter(printer, &ph, &admin_access))) { + printf("OpenPrinter failed, error = %s\n", PrintLastError()); + return -1; + } + + GetPrinterDriver(ph, NULL, 1, NULL, 0, &needed); + if (!needed) { + printf("GetPrinterDriver failed, error = %s\n", PrintLastError()); + ClosePrinter(ph); + return -1; + } + driver_info = malloc(needed); + if (!(GetPrinterDriver(ph, NULL, 1, driver_info, needed, &needed))) { + printf("GetPrinterDriver failed, error = %s\n", PrintLastError()); + ClosePrinter(ph); + return -1; + } + + map_generic_multi_sz(ph, printer, port, DC_BINNAMES, _T("printBinNames"), 24); + map_generic_boolean(ph, printer, port, DC_COLLATE, _T("printCollate")); + map_generic_dword(ph, printer, port, DC_COPIES, _T("printMaxCopies")); + map_generic_dword(ph, printer, port, DC_DRIVER, _T("driverVersion")); + map_generic_boolean(ph, printer, port, DC_DUPLEX, _T("printDuplexSupported")); + map_extents(ph, printer, port); + map_resolution(ph, printer, port); + map_orientation(ph, printer, port); + map_generic_multi_sz(ph, printer, port, DC_PAPERNAMES, _T("printMediaSupported"), 64); +#if (WINVER >= 0x0500) + map_generic_boolean(ph, printer, port, DC_COLORDEVICE, _T("printColor")); + map_generic_multi_sz(ph, printer, port, DC_PERSONALITY, _T("printLanguage"), 64); + map_generic_multi_sz(ph, printer, port, DC_MEDIAREADY, _T("printMediaReady"),64); + map_generic_dword(ph, printer, port, DC_PRINTERMEM, _T("printMemory")); + map_generic_dword(ph, printer, port, DC_PRINTRATE, _T("printRate")); + map_printrateunit(ph, printer, port); +#ifdef DC_STAPLE + map_generic_boolean(ph, printer, port, DC_STAPLE, _T("printStaplingSupported")); +#endif +#ifdef DC_PRINTRATEPPM + map_generic_dword(ph, printer, port, DC_PRINTRATEPPM, _T("printPagesPerMinute")); +#endif +#endif + SetPrinter(ph, 7, (BYTE *) &publish, 0); + ClosePrinter(ph); + return 0; +} diff --git a/examples/printing/readme.prtpub b/examples/printing/readme.prtpub new file mode 100644 index 0000000..319ce60 --- /dev/null +++ b/examples/printing/readme.prtpub @@ -0,0 +1,12 @@ +prtpub.c contains a program which, when compiled with Visual C, can +download a driver for a printer, query the capabilities of the driver, +then write back the DsDriver keys necessary to publish all the fields +of a printer in the directory. After writing back the fields, it issues +a SetPrinter with info level 7, telling the server to publish the +printer. + +It also writes the fields to stdout. + +In order to be distributed, it should be compiled using DLLs for C runtime. + +The program takes the UNC name of a printer as the only argument. diff --git a/examples/printing/smbprint.sysv b/examples/printing/smbprint.sysv new file mode 100644 index 0000000..11fea21 --- /dev/null +++ b/examples/printing/smbprint.sysv @@ -0,0 +1,52 @@ +#!/bin/sh +# +# @(#) smbprint.sysv version 1.0 Ross Wakelin <r.wakelin@march.co.uk> +# +# Version 1.0 13 January 1995 +# modified from the original smbprint (bsd) script +# +# this script is a System 5 printer interface script. It +# uses the smbclient program to print the file to the specified smb-based +# server and service. +# +# To add this to your lp system, copy this file into your samba directory +# (the example here is /opt/samba), modify the server and service variables +# and then execute the following command (as root) +# +# lpadmin -punixprintername -v/dev/null -i/opt/samba/smbprint +# +# where unixprintername is the name that the printer will be known as +# on your unix box. +# +# the script smbprint will be copied into your printer administration +# directory (/usr/lib/lp or /etc/lp) as a new interface +# (interface/unixprintername) +# Then you have to enable unixprintername and accept unixprintername +# +# This script will then be called by the lp service to print the files +# This script will have 6 or more parameters passed to it by the lp service. +# The first five will contain details of the print job, who queued it etc, +# while parameters 6 onwards are a list of files to print. We just +# cat these at the samba client. +# +# Set these to the server and service you wish to print to +# In this example I have a WfWg PC called "lapland" that has a printer +# exported called "printer" with no password. +# +# clear out the unwanted parameters +shift;shift;shift;shift;shift +# now the argument list is just the files to print + +server=admin +service=hplj2 +password="" + +( +# NOTE You may wish to add the line `echo translate' if you want automatic +# CR/LF translation when printing. + echo translate + echo "print -" + cat $* +) | /opt/samba/smbclient "\\\\$server\\$service" $password -N > /dev/null +exit $? + diff --git a/examples/scripts/debugging/linux/backtrace b/examples/scripts/debugging/linux/backtrace new file mode 100644 index 0000000..7d14ff8 --- /dev/null +++ b/examples/scripts/debugging/linux/backtrace @@ -0,0 +1,41 @@ +#! /bin/sh +# +# Author: Andrew Tridgell <tridge at samba dot org> + +# we want everything on stderr, so the program is not disturbed +exec 1>&2 + +BASENAME=$(basename $0) + +test -z ${GDB_BIN} && GDB_BIN=$(type -p gdb) +if [ -z ${GDB_BIN} ]; then + echo "ERROR: ${BASENAME} needs an installed gdb. " + exit 1 +fi + +if [ -z $1 ]; then + echo "ERROR: ${BASENAME} needs a PID. " + exit 1 +fi +PID=$1 + +# use /dev/shm as default temp directory +test -d /dev/shm && + TMP_BASE_DIR=/dev/shm || + TMP_BASE_DIR=/var/tmp +TMPFILE=$(mktemp -p ${TMP_BASE_DIR} backtrace.XXXXXX) +if [ $? -ne 0 ]; then + echo "ERROR: ${basename} can't create temp file in ${TMP_BASE_DIR}. " + exit 1 +fi + +cat <<EOF >"${TMPFILE}" +set height 0 +up 8 +bt full +quit +EOF + +${GDB_BIN} -x "${TMPFILE}" "/proc/${PID}/exe" "${PID}" + +/bin/rm -f "${TMPFILE}" diff --git a/examples/scripts/debugging/smbXsrvdump b/examples/scripts/debugging/smbXsrvdump new file mode 100755 index 0000000..f5c3091 --- /dev/null +++ b/examples/scripts/debugging/smbXsrvdump @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 + +import sys + +sys.path.insert(0, "bin/python") + +import os +import argparse +import struct + +from samba.ndr import ndr_unpack, ndr_print +from samba.dcerpc import smbXsrv +from samba.dcerpc import server_id +import tdb + +def print_watchers(num_watched, blob): + for i in range(0,num_watched): + id = ndr_unpack(server_id.server_id, blob[:24]) + print(ndr_print(id)) + blob = blob[24:] + +def print_record(data, ndr_type, watched, ctdb): + blob = data + + if ctdb: + (rsn, dmaster, reserved1, flags) = struct.unpack('QIII', bytes(blob[:20])) + blob = blob[24:] + print(" ctdb record header: rsn=%lu, dmaster=%u, reserved1=0x%x, flags=0x%x len=%u" % + (rsn, dmaster, reserved1, flags, len(blob))) + if len(blob) == 0: + return + + if watched: + (num_watched, ) = struct.unpack('I', bytes(blob[:4])) + blob = blob[4:] + + deleted_bit = 1<<31 + deleted = num_watched & deleted_bit + + num_watched = num_watched & ~deleted_bit + if num_watched > 0: + if deleted: + deleted_str = "yes" + else: + deleted_str = "no" + print(" num_watched: %d, deleted: %s" % (num_watched, deleted_str)) + print_watchers(num_watched, blob) + blob = blob[num_watched*4:] + + unpacked = ndr_unpack(ndr_type, blob, allow_remaining=True) + print(ndr_print(unpacked)) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('path', help='Path to the TDB file') + parser.add_argument('-c', '--ctdb', + default=False, + action="store_true", + help='The TDB database is from a ctdb cluster') + args = parser.parse_args() + + watched = False + if 'smbXsrv_session' in args.path: + ndr_type = smbXsrv.session_globalB + watched = True + elif 'smbXsrv_open' in args.path: + ndr_type = smbXsrv.open_globalB + elif 'smbXsrv_client' in args.path: + ndr_type = smbXsrv.client_globalB + watched = True + elif 'smbXsrv_tcon' in args.path: + ndr_type = smbXsrv.tcon_globalB + elif 'smbXsrv_version' in args.path: + ndr_type = smbXsrv.version_globalB + else: + raise Exception("Failed to guess NDR type") + + tdb = tdb.Tdb(args.path, 0, tdb.INCOMPATIBLE_HASH, os.O_RDONLY) + + i = 1 + for k in tdb.keys(): + data = tdb.get(k) + print("Record: %d" % i) + print_record(data, ndr_type, watched, args.ctdb) + i = i + 1 + + tdb.close() diff --git a/examples/scripts/debugging/solaris/README b/examples/scripts/debugging/solaris/README new file mode 100644 index 0000000..9e33680 --- /dev/null +++ b/examples/scripts/debugging/solaris/README @@ -0,0 +1,28 @@ +Last update: John H Terpstra - June 27, 2005 + +Subject: This directory will contain debugging tools and tips. + +Notes: Identification and confirmation of some bugs can be difficult. + When such bugs are encountered it is necessary to provide as + sufficient detailed debugging information to assist the developer + both by providing incontrivertable proof of the problem, but also + precise information regarding the values of variables being processed + at the time the problem strikes. + + This directory is the ideal place to locate useful hints, tips and + methods that will help Samba users to provide the information that + developers need. + +============================ Solaris Method A ============================== +File: solaris-oops.sh +Contributor: David Collier-Brown +Date: June 27, 2005 +Method and Use: +To the global stanza of smb.conf add: + panic action = /usr/local/bin/solaris-oops.sh %d + +When the panic action is initiated a voluntary core dump file will be placed +in /var/tmp. Use this method with "log level = 10" and an smbd binary that +has been built with the '-g' option. +============================================================================ + diff --git a/examples/scripts/debugging/solaris/solaris-oops.sh b/examples/scripts/debugging/solaris/solaris-oops.sh new file mode 100644 index 0000000..2d8587d --- /dev/null +++ b/examples/scripts/debugging/solaris/solaris-oops.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# +# solaris_panic_action -- capture supporting information after a failure +# +ProgName=$(basename $0) +LOGDIR=/usr/local/samba/var + +main() +{ + pid=$1 + + if [ $# -lt 1 ]; then + say "$ProgName error: you must supply a pid" + say "Usage: $0 pid" + exit 1 + fi + cat >>$LOGDIR/log.solaris_panic_action <<! + +$(date) +State information and vountary core dump for process $pid + +Related processes were: +$(/usr/bin/ptree $pid) + +Stack(s) were: +$(/usr/bin/pstack $pid) + +Flags were: +$(/usr/bin/pflags $pid) + +Credentials were: +$(/usr/bin/pcred $pid) + +Libraries used were: +$(/usr/bin/pldd $pid) + +Signal-handler settings were: +$(/usr/bin/psig $pid) + +Files and devices in use were: +$(/usr/bin/pfiles $pid) + +Directory in use was: +$(/usr/bin/pwdx $pid) + + +A voluntary core dump was placed in /var/tmp/samba_solaris_panic_action_gcore.$pid +$(gcore -o /var/tmp/samba_solaris_panic_action_gcore $pid) +! +} + +say() +{ + echo "$@" 1>&2 +} + +main "$@" diff --git a/examples/scripts/eventlog/parselog.pl b/examples/scripts/eventlog/parselog.pl new file mode 100644 index 0000000..a2f9a27 --- /dev/null +++ b/examples/scripts/eventlog/parselog.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl +###################################################################### +## +## Simple parselog script for Samba +## +## Copyright (C) Brian Moran 2005. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## +###################################################################### + +## usage: tail -f /var/log/syslog | parselog.pl | eventlogadm -o write "Application" + +while(<>) { + chomp(); + @le = split '\s+',$_,5; + $ln = $le[4]; + $cname = $le[3]; + $outstr = sprintf "TMG: %d\nTMW: %d\nEID: 1000\nETP: INFO\nECT: 0\nRS2: 0\nCRN: 0\nUSL: 0\nSRC: Syslog\nSRN: $cname\nSTR: $ln\nDAT:\n\n",time(),time(); + print $outstr; +} diff --git a/examples/scripts/idmap/README b/examples/scripts/idmap/README new file mode 100644 index 0000000..a8637bb --- /dev/null +++ b/examples/scripts/idmap/README @@ -0,0 +1,168 @@ +idmap script option for flexible UID/GID handling +------------------------------------------------- + +If you are using "idmap backend = tdb2" with winbind in Samba3, then +you have the option of specifying an external script to perform +uid/gid allocation. This can be useful in situations where you are +using AD for authentication, but the AD server is not configured to +supply uid/gid mappings via the services for unix extensions and you +have a need to support a pre-existing system for uid/gid allocation. + +One common situation where this arises is where you have a mixture of +NFS and CIFS clients, and the NFS clients are configured to use NIS +for their id mapping. It is quite common to have an administrative +mechanism in place to ensure that all of the NIS users have a +corresponding AD user account, but there may be no direct mechanism to +ensure that any unix uid/gid attributes in AD match those in NIS. + +In this situation it would normally not be possible to share files +with correct ownership between the CIFS and NFS clients, as winbind +would normally allocate its own set of UIDs from a reserved pool, and +those uids won't match the existing ones in NIS. + +The idmap script option +----------------------- + +To resolve this problem the idmap tdb2 module has the ability to call +out to an external script whenever it needs an unknown SID or UID/GID +for the first time. It is then the job of that script to provide a +mapping consistent with whatever external system is in place (such as +NIS), and return the mapped result to winbind. + +Winbind will then persistently store the result of the mapping, so +that the script is not invoked more than once per user/group. + +To setup the idmap script you need to set the following options: + + idmap backend = tdb2 + idmap script = /usr/local/bin/idmap.sh + +where the location and name of the script is arbitrary. It just needs +to be executable by winbind. + +You then need to stop Samba, delete the key idmap cache files, and +restart Samba. The idmap files that need to be deleted are: + + - gencache.tdb + - winbindd_cache.tdb + - idmap2.tdb + + +Script operation +---------------- + +The script will be called by winbind in one of three ways. + + 1) idmap.sh SIDTOID <SID> + 2) idmap.sh IDTOSID UID <UID> + 2) idmap.sh IDTOSID GID <GID> + +In the first form the script is being asked to map a windows SID (in +the string form "S-*") to a UID or GID. In the second form the script +is being asked to map a UID to a SID, and in the third form it is +being asked to map a GID to a SID. + +SIDTOID +------- + +In the first form the script is expected to output a UID or GID given +a SID. The output format is expected to be like this: + + UID:1234 +or + GID:1122 + +If the SID cannot be found, then the script should output an error +like this: + + ERR:Some error message + +Note that it is common for the external mechanism to not know about +windows SIDs, in which case the script may use the wbinfo command to +ask winbind to change the SID into a username or group name. The +"wbinfo -s" option is the one to use. + + +IDTOSID UID +----------- + +In this form the script is expected to turn a UID into a SID, +returning a result like this: + + SID:S-1-5-21-1110277820-2343689819-414998773-1124 + +or an error like this: + + ERR:Some error message + +If the external mechanism that the script wants to use cannot produce +a SID, but can produce a username, then the script can convert the +username to a SID using the "wbinfo -n" option. + +IDTOSID GID +----------- + +In this form the script is expected to turn a GID into a SID, +returning a result like this: + + SID:S-1-5-21-1110277820-2343689819-414998773-1120 + +or an error like this: + + ERR:Some error message + +If the external mechanism that the script wants to use cannot produce +a SID, but can produce a group name, then the script can convert the +groupname to a SID using the "wbinfo -n" option. + + +Testing the script +------------------ + +It is suggested that you test the script on the command line first, +before using it in winbind. To do that first get a list of users you +would like to test using the command "wbinfo -u". Let's assume one of +those users is "DC01\tridge". You would then test the script as +follows: + + [root ~]# wbinfo -n 'DC01\tridge' + S-1-5-21-1110277820-2343689819-414998773-1124 User (1) + + [root ~]# /usr/local/bin/idmap.sh SIDTOID S-1-5-21-1110277820-2343689819-414998773-1124 + UID:1003 + + [root ~]# /usr/local/bin/idmap.sh IDTOSID UID 1003 + SID:S-1-5-21-1110277820-2343689819-414998773-1124 + +Once those steps pass, you can enable the script in winbind +(remembering to clear the cache tdbs), and test using the id command: + + [root ~]# id 'DC01\tridge' + uid=1003(DC01\tridge) gid=10000009(DC01\domain users) + + +nsswitch.conf +------------- + +When using the idmap script option you setup nsswitch.conf as usual +for winbind, with one addition. If your external idmap mechanism +support nsswitch then you may optionally choose to add it to +nsswitch.conf, but you must add it after the winbind entry. So for +example, if using NIS, you could have a nsswitch.conf entry like this: + + passwd: files winbind nis + group: files winbind nis + +Adding this to nsswitch.conf is not essential, but may be useful for +some local administration tools. + +Sample script +------------- + +This directory contains a simple example script 'idmap_nis.sh' that +provides idmap script support for NIS. To use it you first need to +enable the NIS client on your Samba server, usually by configuring +/etc/yp.conf. See the manual page for yp.conf for details. + +You should test the ypcat and ypmatch commands and make sure they work +before enabling the idmap_nis.sh script. diff --git a/examples/scripts/idmap/idmap_nis.sh b/examples/scripts/idmap/idmap_nis.sh new file mode 100755 index 0000000..a5ea79d --- /dev/null +++ b/examples/scripts/idmap/idmap_nis.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# idmap script to map SIDs to UIDs/GIDs using NIS +# tridge@samba.org June 2009 + +DOMAIN=$(ypdomainname) + +( + date + echo $* +) >>/var/log/samba/idmap.log + +cmd=$1 +shift + +PATH=/usr/bin:bin:$PATH + +shopt -s nocasematch || { + echo "shell option nocasematch not supported" + exit 1 +} + +# map from a domain and name to a uid/gid +map_name() +{ + domain="$1" + name="$2" + ntype="$3" + case $ntype in + 1) + rtype="UID" + map="passwd" + ;; + 2) + rtype="GID" + map="group" + ;; + *) + echo "ERR: bad name type $ntype" + exit 1 + ;; + esac + id=$(ypmatch "$name" "$map".byname 2>/dev/null | cut -d: -f3) + [ -z "$id" ] && { + echo "ERR: bad match for $name in map $map" + exit 1 + } + echo "$rtype":"$id" +} + +# map from a unix id to a name +map_id() +{ + ntype="$1" + id="$2" + case $ntype in + UID) + map="passwd.byuid" + ;; + GID) + map="group.bygid" + ;; + *) + echo "ERR: bad name type $ntype" + exit 1 + ;; + esac + name="$(ypmatch "$id" "$map" 2>/dev/null | cut -d: -f1)" + [ -z "$name" ] && { + echo "ERR: bad match for $name in map $map" + exit 1 + } + echo "$name" +} + +case $cmd in +SIDTOID) + sid=$1 + rid=$(echo $sid | cut -d- -f8) + [ -z "$rid" ] && { + echo "ERR: bad rid in SID $sid" + exit 1 + } + + unset _NO_WINBINDD + # oh, this is ugly. Shell is just not meant for parsing text + fullname=$(wbinfo -s $sid 2>/dev/null) + domain=$(echo $fullname | cut -d'\' -f1) + [[ "$domain" = $DOMAIN ]] || { + echo "ERR: bad domain $domain" + exit 1 + } + name=$(echo $fullname | cut -d'\' -f2) + nwords=$(echo $name | wc -w) + ntype=$(echo $name | cut -d' ' -f$nwords) + nminusone=$(expr $nwords - 1) + name=$(echo $name | cut -d' ' -f-$nminusone) + [ -z "$name" ] && { + echo "ERR: bad name $fullname for SID $sid" + exit 1 + } + map_name "$domain" "$name" "$ntype" + ;; +IDTOSID) + ntype=$1 + id=$2 + name="$(map_id "$ntype" "$id")" + sid="$(wbinfo -n "$name" 2>/dev/null | cut -d' ' -f1)" + [ -z "$sid" ] && { + echo "ERR: name $name not found in ADS" + exit 1 + } + echo "SID:$sid" + ;; +*) + echo "ERR: Unknown command $cmd" + exit 1 + ;; +esac + +exit 0 diff --git a/examples/scripts/mount/mount.smbfs b/examples/scripts/mount/mount.smbfs new file mode 100644 index 0000000..3b57bc5 --- /dev/null +++ b/examples/scripts/mount/mount.smbfs @@ -0,0 +1,115 @@ +#!/bin/bash +# Debian mount.smbfs compatibility wrapper +# Copyright 2007, Steve Langasek <vorlon at debian.org> +# Licensed under the GNU General Public License, version 2. See the +# file /usr/share/common-licenses/GPL or <http://www.gnu.org/copyleft/gpl.txt>. + +# This script accepts all documented mount options for mount.smbfs, +# passing through those that are also recognized by mount.cifs, +# converting those that are not recognized but map to available cifs +# options, and warning about the use of options for which no equivalent +# exists. + +# known bugs: quoted spaces in arguments are not passed intact + +set -e + +# reverse the order of username and password in a "username" parameter, +# taking care to leave any "%password" bit intact + +reverse_username_workgroup() { + local workgroup password username + + username="$1" + case "$username" in + *%*) password="${username#*%}" + username="${username%%%*}" + ;; + *) ;; + esac + case "$username" in + */*) workgroup="${username#*/}" + username="${username%%/*}" + ;; + *) ;; + esac + if [ -n "$workgroup" ]; then + username="$workgroup\\$username" + fi + if [ -n "$password" ]; then + username="$username%$password" + fi + echo "$username" +} + + +# parse out the mount options that have been specified using -o, and if +# necessary, convert them for use by mount.cifs + +parse_mount_options () { + local OLD_IFS IFS options option username + OLD_IFS="$IFS" + IFS="," + options="" + workgroup="" + password="" + + for option in $@; do + case "$option" in + sockopt=* | scope=* | codepage=* | ttl=* | debug=*) + echo "Warning: ignoring deprecated smbfs option '$option'" >&2 + ;; + + krb) + options="$options${options:+,}sec=krb5" + ;; + + guest) + echo "Warning: mapping 'guest' to 'guest,sec=none'" >&2 + options="$options${options:+,}guest,sec=none" + ;; + + # username and workgroup are reversed in username= arguments, + # so need to be parsed out + username=*/*) + IFS="$OLD_IFS" + username="${option#username=}" + username="$(reverse_username_workgroup "$username")" + IFS="," + options="$options${options:+,}username=$username" + ;; + + *) + options="$options${options:+,}$option" + ;; + esac + done + IFS="$OLD_IFS" + echo $options +} + +args=() +while [ "$#" -gt 0 ]; do + case "$1" in + -o*) + arg=${1#-o} + shift + if [ -z "$arg" ]; then + arg=$1 + shift + fi + arg="$(parse_mount_options "$arg")" + if [ -n "$arg" ]; then + args=("${args[@]}" "-o" "$arg") + fi + ;; + *) + args=("${args[@]}" "$1") + shift + ;; + esac +done + +USER="$(reverse_username_workgroup "$USER")" + +exec /sbin/mount.cifs "${args[@]}" diff --git a/examples/scripts/nmb/findsmb b/examples/scripts/nmb/findsmb new file mode 100755 index 0000000..5c668f3 --- /dev/null +++ b/examples/scripts/nmb/findsmb @@ -0,0 +1,160 @@ +#!/usr/bin/env perl +# +# Prints info on all smb responding machines on a subnet. +# This script needs to be run on a machine without nmbd running and be +# run as root to get correct info from WIN95 clients. +# +# syntax: +# findsmb [-d|-D] [-r] [subnet broadcast address] +# +# with no argument it will list machines on the current subnet +# +# There will be a "+" in front of the workgroup name for machines that are +# local master browsers for that workgroup. There will be an "*" in front +# of the workgroup name for machines that are the domain master browser for +# that workgroup. +# +# Options: +# +# -d|-D enable debug +# -r add -r option to nmblookup when finding netbios name +# + +$SAMBABIN = "/usr/bin"; + +for ($i = 0; $i < 2; $i++) { # test for -d and -r options + $_ = shift; + if (m/-d|-D/) { + $DEBUG = 1; + } elsif (m/-r/) { + $R_OPTION = "-r"; + } +} + +if ($_) { # set broadcast address if it was specified + $BCAST = "-B $_"; +} + + +###################################################################### +# do numeric sort on last field of IP address +sub ipsort +{ + @t1 = split(/\./,$a); + @t2 = split(/\./,$b); + @t1[3] <=> @t2[3]; +} +###################################################################### + +# look for all machines that respond to a name lookup + +open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*' --debuglevel=0|") || + die("Can't run nmblookup '*'.\n"); + +# get rid of all lines that are not a response IP address, +# strip everything but IP address and sort by last field in address + +@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>); + +# print header info +print "\n *=DMB\n"; +print " +=LMB\n"; +print "IP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n"; +print "---------------------------------------------------------------------\n"; + +foreach $ip (@ipaddrs) # loop through each IP address found +{ + $ip =~ s/\n//; # strip newline from IP address + + # find the netbios names registered by each machine + + open(NMBLOOKUP,"$SAMBABIN/nmblookup $R_OPTION -A $ip --debuglevel=0|") || + die("Can't get nmb name list.\n"); + @nmblookup = <NMBLOOKUP>; + close NMBLOOKUP; + + # get the first <00> name + + @name = grep(/<00>/,@nmblookup); + $_ = @name[0]; + + if ($_) { # we have a netbios name + if (/GROUP/) { # is it a group name + ($name, $aliases, $type, $length, @addresses) = + gethostbyaddr(pack('C4',split('\.',$ip)),2); + if (! $name) { # could not get name + $name = "unknown nis name"; + } + } else { + # The Netbios name can contain lot of characters also '<' '>' + # and spaces. The following cure inside name space but not + # names starting or ending with spaces + /(.{1,15})\s+<00>\s+/; + $name = $1; + $name =~ s/^\s+//g; + } + + # do an smbclient command on the netbios name. + + if ( "$name" ) { + open(SMB,"$SAMBABIN/smbclient -L $name -I $ip -N --debuglevel=1 2>&1 |") || + die("Can't do smbclient command.\n"); + @smb = <SMB>; + close SMB; + + if ($DEBUG) { # if -d flag print results of nmblookup and smbclient + print "===============================================================\n"; + print @nmblookup; + print @smb; + } + + # look for the OS= string + + @info = grep(/OS=/,@smb); + $_ = @info[0]; + if ($_) { # we found response + s/Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter + + } else { # no OS= string in response (WIN95 client) + + # for WIN95 clients get workgroup name from nmblookup response + @name = grep(/<00> - <GROUP>/,@nmblookup); + $_ = @name[0]; + if ($_) { + # Same as before for space and characters + /(.{1,15})\s+<00>\s+/; + $_ = "[$1]"; + } else { + $_ = "Unknown Workgroup"; + } + } + } + + # see if machine registered a local master browser name + if (grep(/<1d>/,@nmblookup)) { + $master = '+'; # indicate local master browser + if (grep(/<1b>/,@nmblookup)) { # how about domain master browser? + $master = '*'; # indicate domain master browser + } + } else { + $master = ' '; # not a browse master + } + + # line up info in 3 columns + + print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n"; + + } else { # no netbios name found + # try getting the host name + ($name, $aliases, $type, $length, @addresses) = + gethostbyaddr(pack('C4',split('\.',$ip)),2); + if (! $name) { # could not get name + $name = "unknown nis name"; + } + if ($DEBUG) { # if -d flag print results of nmblookup + print "===============================================================\n"; + print @nmblookup; + } + print "$ip".' 'x(16-length($ip))."$name\n"; + } +} diff --git a/examples/scripts/nmb/findsmb.1.xml b/examples/scripts/nmb/findsmb.1.xml new file mode 100644 index 0000000..6b35410 --- /dev/null +++ b/examples/scripts/nmb/findsmb.1.xml @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc"> +<refentry id="findsmb.1"> + +<refmeta> + <refentrytitle>findsmb</refentrytitle> + <manvolnum>1</manvolnum> + <refmiscinfo class="source">Samba</refmiscinfo> + <refmiscinfo class="manual">User Commands</refmiscinfo> + <refmiscinfo class="version">&doc.version;</refmiscinfo> +</refmeta> + + +<refnamediv> + <refname>findsmb</refname> + <refpurpose>list info about machines that respond to SMB + name queries on a subnet</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>findsmb</command> + <arg choice="opt">subnet broadcast address</arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>This perl script is part of the <citerefentry> + <refentrytitle>samba</refentrytitle><manvolnum>7</manvolnum></citerefentry> + suite.</para> + + <para><command>findsmb</command> is a perl script that + prints out several pieces of information about machines + on a subnet that respond to SMB name query requests. + It uses <citerefentry><refentrytitle>nmblookup</refentrytitle><manvolnum>1</manvolnum></citerefentry> + and <citerefentry><refentrytitle>smbclient</refentrytitle><manvolnum>1</manvolnum></citerefentry> + to obtain this information. + </para> +</refsect1> + +<refsect1> + <title>OPTIONS</title> + + <variablelist> + <varlistentry> + <term>-r</term> + <listitem><para>Controls whether <command>findsmb</command> takes + bugs in Windows95 into account when trying to find a Netbios name + registered of the remote machine. This option is disabled by default + because it is specific to Windows 95 and Windows 95 machines only. + If set, <citerefentry><refentrytitle>nmblookup</refentrytitle><manvolnum>1</manvolnum></citerefentry> + will be called with <constant>-B</constant> option.</para></listitem> + </varlistentry> + <varlistentry> + <term>subnet broadcast address</term> + <listitem><para>Without this option, <command>findsmb + </command> will probe the subnet of the machine where + <citerefentry><refentrytitle>findsmb</refentrytitle><manvolnum>1</manvolnum></citerefentry> + is run. This value is passed to + <citerefentry><refentrytitle>nmblookup</refentrytitle><manvolnum>1</manvolnum></citerefentry> + as part of the <constant>-B</constant> option.</para></listitem> + </varlistentry> + </variablelist> +</refsect1> + +<refsect1> + <title>EXAMPLES</title> + + <para>The output of <command>findsmb</command> lists the following + information for all machines that respond to the initial + <command>nmblookup</command> for any name: IP address, NetBIOS name, + Workgroup name, operating system, and SMB server version.</para> + + <para>There will be a '+' in front of the workgroup name for + machines that are local master browsers for that workgroup. There + will be an '*' in front of the workgroup name for + machines that are the domain master browser for that workgroup. + Machines that are running Windows for Workgroups, Windows 95 or + Windows 98 will + not show any information about the operating system or server + version.</para> + + <para>The command with <constant>-r</constant> option + must be run on a system without <citerefentry> + <refentrytitle>nmbd</refentrytitle><manvolnum>8</manvolnum> + </citerefentry> running. + + If <command>nmbd</command> is running on the system, you will + only get the IP address and the DNS name of the machine. To + get proper responses from Windows 95 and Windows 98 machines, + the command must be run as root and with <constant>-r</constant> + option on a machine without <command>nmbd</command> running.</para> + + <para>For example, running <command>findsmb</command> + without <constant>-r</constant> option set would yield output similar + to the following</para> + +<programlisting> +IP ADDR NETBIOS NAME WORKGROUP/OS/VERSION +--------------------------------------------------------------------- +192.168.35.10 MINESET-TEST1 [DMVENGR] +192.168.35.55 LINUXBOX *[MYGROUP] [Unix] [Samba 2.0.6] +192.168.35.56 HERBNT2 [HERB-NT] +192.168.35.63 GANDALF [MVENGR] [Unix] [Samba 2.0.5a for IRIX] +192.168.35.65 SAUNA [WORKGROUP] [Unix] [Samba 1.9.18p10] +192.168.35.71 FROGSTAR [ENGR] [Unix] [Samba 2.0.0 for IRIX] +192.168.35.78 HERBDHCP1 +[HERB] +192.168.35.88 SCNT2 +[MVENGR] [Windows NT 4.0] [NT LAN Manager 4.0] +192.168.35.93 FROGSTAR-PC [MVENGR] [Windows 5.0] [Windows 2000 LAN Manager] +192.168.35.97 HERBNT1 *[HERB-NT] [Windows NT 4.0] [NT LAN Manager 4.0] +</programlisting> + +</refsect1> + + +<refsect1> + <title>VERSION</title> + + <para>This man page is part of version &doc.version; of + the Samba suite.</para> +</refsect1> + +<refsect1> + <title>SEE ALSO</title> + <para><citerefentry> + <refentrytitle>nmbd</refentrytitle><manvolnum>8</manvolnum> + </citerefentry>, + <citerefentry><refentrytitle>smbclient</refentrytitle><manvolnum>1</manvolnum> + </citerefentry>, and <citerefentry><refentrytitle>nmblookup</refentrytitle> + <manvolnum>1</manvolnum></citerefentry> + </para> +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para>The original Samba software and related utilities + were created by Andrew Tridgell. Samba is now developed + by the Samba Team as an Open Source project similar + to the way the Linux kernel is developed.</para> +</refsect1> + +</refentry> diff --git a/examples/scripts/printing/cups/smbaddprinter.pl b/examples/scripts/printing/cups/smbaddprinter.pl new file mode 100755 index 0000000..aee2020 --- /dev/null +++ b/examples/scripts/printing/cups/smbaddprinter.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl +## Add printer script for samba, APW, and cups +## Copyright (C) Jeff Hardy <hardyjm@potsdam.edu> 2004 +## +## This program is free software; you can redistribute it +## and/or modify it under the terms of the GNU General +## Public License as published by the Free Software Foundation; +## Either version 3 of the License, or (at your option) any +## later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, see <http://www.gnu.org/licenses/>. + +@argv = @ARGV; + +# take in args +my $lpname=shift(@argv); # printer name +my $shname=shift(@argv); # share name -> used for CUPS queue name +my $portname=shift(@argv); # port name +my $drivername=shift(@argv); # driver name -> used for CUPS description +my $location=shift(@argv); # location -> used for CUPS device URI +my $win9x=shift(@argv); # win9x location + +#check for location syntax +#if no protocol specified... +if ($location !~ m#:/#){ + #assume an lpd printer + $location = "lpd://".$location; +} +#else, simply pass the URI on to the lpadmin command + +#run the cups lpadmin command to add the printer +system("/usr/sbin/lpadmin -p $shname -D \"$drivername\" -E -v $location"); + diff --git a/examples/scripts/printing/cups/smbdelprinter.pl b/examples/scripts/printing/cups/smbdelprinter.pl new file mode 100755 index 0000000..23adeb7 --- /dev/null +++ b/examples/scripts/printing/cups/smbdelprinter.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl +## Delete printer script for samba, APW, and cups +## Copyright (C) Gerald (Jerry) Carter <jerry@samba.rog> 2004 +## +## This program is free software; you can redistribute it +## and/or modify it under the terms of the GNU General +## Public License as published by the Free Software Foundation; +## Either version 3 of the License, or (at your option) any +## later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, see <http://www.gnu.org/licenses/>. + +@argv = @ARGV; + +# take in args +my $lpname=shift(@argv); # printer name + +system("/usr/sbin/lpadmin -x $lpname"); + diff --git a/examples/scripts/users_and_groups/adduserstogroups.pl b/examples/scripts/users_and_groups/adduserstogroups.pl new file mode 100755 index 0000000..99837f9 --- /dev/null +++ b/examples/scripts/users_and_groups/adduserstogroups.pl @@ -0,0 +1,166 @@ +#!/usr/bin/perl + +# +# adduserstogroups.pl +# +# add single or continuously numbered domain users +# to a given single group or list of groups +# +# Copyright (C) Michael Adam <obnox@samba.org> 2007 +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see <http://www.gnu.org/licenses/>. +# + +# +# WARNING: This script is still rather crude. +# + +use strict; +use Getopt::Std; + +my $net_cmd = "net"; + +# defaults: + +my $server; +my $num_members = 1; +my $startmem; # if empty, don't add numbers to member prefix +my $member_prefix; # name prefix for member +my $num_groups = 1; +my $startgroup; # if empty, don't add numbers to group prefix +my $group_prefix; # name prefix for group +my $path; # path to rpcclient command +my $net_path = $net_cmd; +my $creds; + +sub usage { + print "USAGE: $0 [-h] -S server -U user\%pass \\\n" + . "\t-m member [-s startmem] [-n nummem] \\\n" + . "\t-g group [-G startgroup] [-N numgroups] \\\n" + . "\t[-P path]\n"; +} + +# parse commandline: + +my %options = (); +getopts("U:S:m:s:n:g:G:N:P:h", \%options); + +if (exists($options{h})) { + usage(); + exit 0; +} + +if (exists($options{g})) { + $group_prefix = $options{g}; +} +else { + print "ERROR: mandatory argument '-g' missing\n"; + usage(); + exit 1; +} + +if (exists($options{U})) { + $creds = "-U $options{U}"; + if ($creds !~ '%') { + print "ERROR: you need to specify credentials in the form -U user\%pass\n"; + usage(); + exit 1; + } +} +else { + print "ERROR: mandatory argument '-U' missing\n"; + usage(); + exit 1; +} + +if (exists($options{S})) { + $server = $options{S}; +} +else { + print "ERROR: mandatory argument '-S' missing\n"; + usage(); + exit 1; +} + +if (exists($options{s})) { + $startmem = $options{s}; +} + +if (exists($options{n})) { + $num_members = $options{n}; +} + +if (exists($options{m})) { + $member_prefix = $options{m}; +} +else { + print "ERROR: mandatory argument '-m' missing\n"; + usage(); + exit 1; +} + +if (exists($options{G})) { + $startgroup = $options{G}; +} + +if (exists($options{N})) { + $num_groups = $options{N}; +} + +if (exists($options{P})) { + $path = $options{p}; + $net_path = "$path/$net_cmd"; +} + +if (@ARGV) { + print "ERROR: junk on the command line ('" . join(" ", @ARGV) . "')...\n"; + usage(); + exit 1; +} + +# utility functions: + +sub do_add { + my $member_name = shift; + my $group_name = shift; + print "adding member $member_name to group $group_name\n"; + system("$net_path rpc -I $server ".$creds." group addmem $group_name $member_name"); +} + +sub add_group_loop { + my $member_name = shift; + + if ("x$startgroup" eq "x") { + do_add($member_name, $group_prefix); + } + else { + for (my $groupnum = 1; $groupnum <= $num_groups; ++$groupnum) { + do_add($member_name, + sprintf("%s%.05d", $group_prefix, $startgroup + $groupnum - 1)); + } + } +} + + +# main: + +if ("x$startmem" eq "x") { + add_group_loop($member_prefix); +} +else { + for (my $memnum = 1; $memnum <= $num_members; ++$memnum) { + add_group_loop(sprintf("%s%.05d", $member_prefix, $startmem + $memnum - 1)); + } +} + diff --git a/examples/scripts/users_and_groups/createdomobj.pl b/examples/scripts/users_and_groups/createdomobj.pl new file mode 100755 index 0000000..d53aefe --- /dev/null +++ b/examples/scripts/users_and_groups/createdomobj.pl @@ -0,0 +1,159 @@ +#!/usr/bin/perl + +# +# createdomobj.pl +# +# create single or continuously numbered domain +# users/groups/aliases via rpc +# +# Copyright (C) Michael Adam <obnox@samba.org> 2007 +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see <http://www.gnu.org/licenses/>. +# + +# +# WARNING: This script is still rather crude. +# + +use strict; +use Getopt::Std; + + +my $target_type = "group"; # what type of object to create +my $rpc_cmd = "createdom".$target_type; +my $rpccli_cmd = "rpcclient"; + +# defaults: + +my $server; +my $num_targets = 1; +my $startnum; # if empty, don't add numbers to prefix +my $prefix; # name-prefix +my $path; # path to rpcclient command +my $rpccli_path = $rpccli_cmd; +my $creds; + +sub usage { + print "USAGE: $0 [-h] -S server -U user\%pass [-p prefix] \\\n" + . "\t[-t {alias|group|user}] [-s startnum] [-n numobjs] [-P path] \n"; +} + +# parse commandline: + +my %options = (); +getopts("U:t:S:s:n:p:P:h", \%options); + +if (exists($options{h})) { + usage(); + exit 0; +} + +if (exists($options{t})) { + $target_type = $options{t}; + if ($target_type !~ /^(alias|user|group)$/) { + print "ERROR: invalid target type given\n"; + usage(); + exit 1; + } + $rpc_cmd = "createdom".$target_type; +} + +if (exists($options{U})) { + $creds = "-U $options{U}"; + if ($creds !~ '%') { + print "ERROR: you need to specify credentials in the form -U user\%pass\n"; + usage(); + exit 1; + } +} +else { + print "ERROR: mandatory argument '-U' missing\n"; + usage(); + exit 1; +} + +if (exists($options{S})) { + $server = $options{S}; +} +else { + print "ERROR: mandatory argument '-S' missing\n"; + usage(); + exit 1; +} + +if (exists($options{s})) { + $startnum = $options{s}; +} + +if (exists($options{n})) { + $num_targets = $options{n}; +} + +if (exists($options{p})) { + $prefix = $options{p}; +} else { + $prefix = $target_type; +} + +if (exists($options{P})) { + $path = $options{p}; + $rpccli_path = "$path/$rpccli_cmd"; +} + +if (@ARGV) { + print "ERROR: junk on the command line ('" . join(" ", @ARGV) . "')...\n"; + usage(); + exit 1; +} + +# utility functions: + +sub open_rpc_pipe { + print "opening rpc pipe\n"; + open(IPC, "| $rpccli_cmd $server $creds -d0") or + die "error opening rpc pipe."; +} + +sub close_rpc_pipe { + print "closing rpc pipe\n"; + close(IPC); +} + +sub do_create { + my $target_name = shift; + print "creating $target_type $target_name\n"; + print IPC "$rpc_cmd $target_name\n"; +} + +# main: + +open_rpc_pipe(); + +if ("x$startnum" eq "x") { + do_create($prefix); +} +else { + for (my $num = 1; $num <= $num_targets; ++$num) { + do_create(sprintf "%s%.05d", $prefix, $startnum + $num - 1); + if (($num) % 500 == 0) { + printf("500 ".$target_type."s created\n"); + close_rpc_pipe(); + sleep 2; + open_rpc_pipe(); + } + } +} + +close_rpc_pipe(); + diff --git a/examples/scripts/vfs/media_harmony/trigger_avid_update.py b/examples/scripts/vfs/media_harmony/trigger_avid_update.py new file mode 100755 index 0000000..7d724ef --- /dev/null +++ b/examples/scripts/vfs/media_harmony/trigger_avid_update.py @@ -0,0 +1,106 @@ +#!/usr/bin/python +import os +import socket +import sys +import stat + +###################################################################### +## +## trigger_avid_update.py for media_harmony VFS module. +## +## Copyright (C) Andrew Klaassen 2012. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## +###################################################################### + + +# +# Change avid_shares and ip_prefix as appropriate for your network. +# + +avid_shares = ( + '\\\\mediaharmony01\\project1\\', + '\\\\mediaharmony01\\project2\\', + '\\\\mediaharmony01\\project3\\', +) + +ip_prefix = '192.168.1.' + + +if __name__ == "__main__": + my_ips = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if ip[:len(ip_prefix)] == ip_prefix] + if not my_ips: + print 'No IP address found. Aborting.' + dummy = raw_input("\nPress Enter to finish: ") + sys.exit() + + my_ip = my_ips[0] + my_name = os.environ.get('USERNAME') + + for avid_share in avid_shares: + media_dirs = [] + omfi_dir = os.path.join(avid_share, 'OMFI MediaFiles') + if os.path.exists(omfi_dir): + media_dirs.append(omfi_dir) + mxf_root = os.path.join(avid_share, 'Avid MediaFiles', 'MXF') + if os.path.exists(mxf_root): + mxf_children = os.listdir(mxf_root) + for child in mxf_children: + fullpath = os.path.join(mxf_root, child) + if os.path.isdir(fullpath): + media_dirs.append(fullpath) + + for media_dir in media_dirs: + + print '\nChecking %s...' % media_dir + + fakepath = '%s_%s_%s' % (media_dir, my_ip, my_name) + print '...fakepath: %s' % fakepath + + db = os.path.join(media_dir, 'msmMMOB.mdb') + print '...Checking for %s' % db + if os.path.exists(db): + print '......found %s.' % db + db_mtime = os.stat(db)[stat.ST_MTIME] + newer_file = False + for child in os.listdir(media_dir): + if child == 'msmMMOB.mdb' or child == 'msmFMID.pmr': + continue + child_mtime = os.stat(os.path.join(media_dir, child))[stat.ST_MTIME] + if child_mtime > db_mtime: + print '......found newer file %s' % child + newer_file = True + break + else: + print '......no %s.' % db + newer_file = True + + if newer_file: + utime = None # Sets to current time. + print '...Setting fake mtime to NOW. Will trigger re-index.' + else: + mtime = os.stat(media_dir)[stat.ST_MTIME] + utime = (mtime, mtime) + print '...Setting fake mtime to media_dir mtime. No re-index.' + + if not os.path.exists(fakepath): + tmp_fakepath = '%s.tmp' % fakepath + open(tmp_fakepath, 'a').close() + os.utime(tmp_fakepath, utime) + os.rename(tmp_fakepath, fakepath) + else: + os.utime(fakepath, utime) + + dummy = raw_input("\nPress Enter to finish: ") diff --git a/examples/scripts/vfs/virusfilter/virusfilter-notify.ksh b/examples/scripts/vfs/virusfilter/virusfilter-notify.ksh new file mode 100644 index 0000000..a07b914 --- /dev/null +++ b/examples/scripts/vfs/virusfilter/virusfilter-notify.ksh @@ -0,0 +1,284 @@ +#!/bin/ksh +## +## Samba-VirusFilter VFS modules +## Copyright (C) 2010-2016 SATOH Fumiyasu @ OSS Technology Corp., Japan +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. +## + +set -u + +pdie() { echo "$0: ERROR: ${1-}" 1>&2; exit "${2-1}"; } + +## ====================================================================== + +sendmail="${VIRUSFILTER_NOTIFY_SENDMAIL_COMMAND:-/usr/sbin/sendmail}" +sendmail_opts="${VIRUSFILTER_NOTIFY_SENDMAIL_OPTIONS:-}" + +smbclient="${VIRUSFILTER_NOTIFY_SMBCLIENT_COMMAND:-@SAMBA_BINDIR@/smbclient}" +smbclient_opts="${VIRUSFILTER_NOTIFY_SMBCLIENT_OPTIONS:-}" + +## ====================================================================== + +if [ -n "${VIRUSFILTER_RESULT_IS_CACHE-}" ]; then + ## Result is cache. Ignore! + exit 0 +fi + +if [ ! -t 1 ] && [ -z "${VIRUSFILTER_NOTIFY_BG-}" ]; then + export VIRUSFILTER_NOTIFY_BG=1 + "$0" ${1+"$@"} </dev/null >/dev/null & + exit 0 +fi + +## ---------------------------------------------------------------------- + +if [ -n "${VIRUSFILTER_INFECTED_FILE_ACTION-}" ]; then + report="$VIRUSFILTER_INFECTED_FILE_REPORT" +else + report="$VIRUSFILTER_SCAN_ERROR_REPORT" +fi + +if [ X"$VIRUSFILTER_SERVER_NAME" != X"$VIRUSFILTER_SERVER_IP" ]; then + server_name="$VIRUSFILTER_SERVER_NAME" +else + server_name="$VIRUSFILTER_SERVER_NETBIOS_NAME" +fi + +if [ X"$VIRUSFILTER_CLIENT_NAME" != X"$VIRUSFILTER_CLIENT_IP" ]; then + client_name="$VIRUSFILTER_CLIENT_NAME" +else + client_name="$VIRUSFILTER_CLIENT_NETBIOS_NAME" +fi + +mail_to="" +winpopup_to="" +subject_prefix="" +sender="" +from="" +cc="" +bcc="" +content_type="text/plain" +content_encoding="UTF-8" + +cmd_usage="Usage: $0 [OPTIONS] + +Options: + --mail-to ADDRESS + Send a notice message to this e-mail address(es) + --winpopup-to NAME + Send a \"WinPopup\" message to this NetBIOS name + --sender ADDRESS + Envelope sender address for mail + --from ADDRESS + From: e-mail address for mail + --cc ADDRESS + Cc: e-mail address(es) for mail + --bcc ADDRESS + Bcc: e-mail address(es) for mail + --subject-prefix PREFIX + Subject: prefix string for mail + --content-type TYPE + --content-encoding ENCODING + Content-Type: TYPE; charset=\"ENCODING\" for mail [$content_type; charset=\"$content_encoding\"] + --header-file FILE + Prepend the content of FILE to the message + --footer-file FILE + Append the content of FILE to the message +" + +## ---------------------------------------------------------------------- + +getopts_want_arg() +{ + if [ "$#" -lt 2 ]; then + pdie "Option requires an argument: $1" + fi + if [ "$#" -ge 3 ]; then + if expr x"$2" : x"$3\$" >/dev/null; then + : OK + else + pdie "Invalid value for option: $1 $2" + fi + fi +} + +while [ "$#" -gt 0 ]; do + OPT="$1"; shift + case "$OPT" in + --help) + echo "$cmd_usage" + exit 0 + ;; + --mail-to) + getopts_want_arg "$OPT" ${1+"$1"} + mail_to="${mail_to:+$mail_to, }$1"; shift + ;; + --winpopup-to) + getopts_want_arg "$OPT" ${1+"$1"} + winpopup_to="$1"; shift + ;; + --sender) + getopts_want_arg "$OPT" ${1+"$1"} + sender="$1"; shift + ;; + --from) + getopts_want_arg "$OPT" ${1+"$1"} + from="$1"; shift + ;; + --cc) + getopts_want_arg "$OPT" ${1+"$1"} + cc="${cc:+$cc, }$1"; shift + ;; + --bcc) + getopts_want_arg "$OPT" ${1+"$1"} + bcc="${bcc:+$bcc, }$1"; shift + ;; + --subject-prefix) + getopts_want_arg "$OPT" ${1+"$1"} + subject_prefix="$1"; shift + ;; + --content-type) + getopts_want_arg "$OPT" ${1+"$1"} + content_type="$1"; shift + ;; + --content-encoding) + getopts_want_arg "$OPT" ${1+"$1"} + content_encoding="$1"; shift + ;; + --header-file) + getopts_want_arg "$OPT" ${1+"$1"} + header_file="$1"; shift + ;; + --footer-file) + getopts_want_arg "$OPT" ${1+"$1"} + footer_file="$1"; shift + ;; + --) + break + ;; + -*) + pdie "Invalid option: $OPT" + ;; + *) + set -- "$OPT" ${1+"$@"} + break + ;; + esac +done + +[ -z "$sender" ] && sender="$from" +subject="$subject_prefix$report" + +## ====================================================================== + +msg_header="\ +Subject: $subject +Content-Type: $content_type; charset=$content_encoding +X-VIRUSFILTER-Version: $VIRUSFILTER_VERSION +X-VIRUSFILTER-Module-Name: $VIRUSFILTER_MODULE_NAME +" + +if [ -n "${VIRUSFILTER_MODULE_VERSION-}" ]; then + msg_header="${msg_header}\ +X-VIRUSFILTER-Module-Version: $VIRUSFILTER_MODULE_VERSION +" +fi + +if [ -n "${from-}" ]; then + msg_header="${msg_header}\ +From: $from +" +fi + +if [ -n "${mail_to-}" ]; then + msg_header="${msg_header}\ +To: $mail_to +" +fi + +if [ -n "${cc-}" ]; then + msg_header="${msg_header}\ +Cc: $cc +" +fi + +if [ -n "${bcc-}" ]; then + msg_header="${msg_header}\ +Bcc: $bcc +" +fi + +## ---------------------------------------------------------------------- + +msg_body="" + +if [ -n "${header_file-}" ] && [ -f "$header_file" ]; then + msg_body="${msg_body}\ +`cat "$header_file"` +" +fi + +msg_body="${msg_body}\ +Server: $server_name ($VIRUSFILTER_SERVER_IP) +Server PID: $VIRUSFILTER_SERVER_PID +Service name: $VIRUSFILTER_SERVICE_NAME +Service path: $VIRUSFILTER_SERVICE_PATH +Client: $client_name ($VIRUSFILTER_CLIENT_IP) +User: $VIRUSFILTER_USER_DOMAIN\\$VIRUSFILTER_USER_NAME +" + +if [ -n "${VIRUSFILTER_INFECTED_FILE_ACTION-}" ]; then + msg_body="${msg_body}\ +Infected file report: $VIRUSFILTER_INFECTED_FILE_REPORT +" + msg_body="${msg_body}\ +Infected file path: $VIRUSFILTER_SERVICE_PATH/$VIRUSFILTER_INFECTED_SERVICE_FILE_PATH +" + msg_body="${msg_body}\ +Infected file action: $VIRUSFILTER_INFECTED_FILE_ACTION +" +else + msg_body="${msg_body}\ +Scan error report: $VIRUSFILTER_SCAN_ERROR_REPORT +Scan error file path: $VIRUSFILTER_SERVICE_PATH/$VIRUSFILTER_SCAN_ERROR_SERVICE_FILE_PATH +" +fi + +if [ -n "${VIRUSFILTER_QUARANTINED_FILE_PATH-}" ]; then + msg_body="${msg_body}\ +Quarantined/Renamed file path: ${VIRUSFILTER_QUARANTINED_FILE_PATH-} +" +fi + +if [ -n "${footer_file-}" ] && [ -f "$footer_file" ]; then + msg_body="${msg_body}\ +`cat "$footer_file"` +" +fi + +## ====================================================================== + +if [ -n "$mail_to" ]; then + (echo "$msg_header"; echo "$msg_body") \ + |"$sendmail" -t -i ${sender:+-f "$sender"} $sendmail_opts +fi + +if [ -n "$winpopup_to" ]; then + echo "$msg_body" \ + |"$smbclient" -M "$winpopup_to" -U% $smbclient_opts \ + >/dev/null +fi + +exit 0 diff --git a/examples/scripts/wins_hook/README b/examples/scripts/wins_hook/README new file mode 100644 index 0000000..1147f57 --- /dev/null +++ b/examples/scripts/wins_hook/README @@ -0,0 +1,8 @@ +This is an example script for doing dynamic DNS updates from the WINS +database. You use this by putting the full path to the script in the +"wins hook" option in smb.conf. Remember to mark the script executable +and to set the right domain at the top of the script. + +See the BIND documentation for how to enable dynamic DNS +updates. Remember to restrict the updates as far as you can to reduce +the security risks inherent in dynamic DNS. diff --git a/examples/scripts/wins_hook/dns_update b/examples/scripts/wins_hook/dns_update new file mode 100644 index 0000000..14fc1fe --- /dev/null +++ b/examples/scripts/wins_hook/dns_update @@ -0,0 +1,92 @@ +#!/bin/sh +# +# Example script for "wins hook". This attempts to update the DNS with +# new A records for the NETBIOS name that Samba passes us. We do this +# the simple way, by deleting all DNS records for the name and then +# re-adding all the expected 'A' records. +# +# Written by Stephen Rothwell <sfr@linuxcare.com> +# + +# +# Configurable things +# +# The domain in which to create names +# YOU MUST CHANGE THIS +# N.B. include the trailing dot +# +# It is a good idea to use a subdomain of your primary domain to ensure +# that rogue machines can't take over (or delete) important names on +# your network. +DOMAIN=wins.example.com. + +# +# The DNS TTL to give the records (in seconds) +# +TTL=3600 +# +# NETBIOS name types that we want to create DNS records for: +# 20 is server +# 00 is workstation +# 03 is user +# +USEFUL_TYPES="20 00 03" +# +# The name of a cache file to use to avoid continual updates +# of the same name and IP addresses. If you comment this out +# then the cache is not kept at all. +# +#CACHE_FILE=/usr/local/samba/var/wins_update.cache + +if [ $# -lt 4 ]; then + echo "Usage: $0 op name type ttl [ip_addr ...]" 1>&2 + echo " op is one of add, refresh, delete" 1>&2 + echo " name is the NETBIOS name" 1>&2 + echo " type is the NETBIOS name type" 1>&2 + echo " ttl is the NETBIOS time to live" 1>&2 + echo " ip_addr's are the remaining IP addresses for this name" 1>&2 + exit 1 +fi + +NSUPDATE=$(which nsupdate) +[ -x "$NSUPDATE" ] || NSUPDATE=/usr/bin/nsupdate +[ -x "$NSUPDATE" ] || NSUPDATE=/sbin/nsupdate +[ -x "$NSUPDATE" ] || NSUPDATE=/usr/sbin/nsupdate +[ -x "$NSUPDATE" ] || { + echo "Cannot find nsupdate." 1>&2 + exit 1 +} + +OP=$1 +NAME=$2 +TYPE=$3 +WINS_TTL=$4 +shift 4 +IP_ADDRS="$@" + +do_update=0 +for i in $USEFUL_TYPES; do + [ "$TYPE" = "$i" ] && do_update=1 +done +[ $do_update = 1 ] || exit 0 + +if [ -n "$CACHE_FILE" ]; then + if [ -r "$CACHE_FILE" ]; then + fgrep -q -x -i "$NAME $IP_ADDRS" "$CACHE_FILE" && + exit 0 + grep -v -i "^$NAME " "$CACHE_FILE" >"$CACHE_FILE".$$ + fi + echo "$NAME $IP_ADDRS" >>"$CACHE_FILE".$$ + mv "$CACHE_FILE" "$CACHE_FILE".old 2>/dev/null + mv "$CACHE_FILE".$$ "$CACHE_FILE" +fi + +{ + echo update delete $NAME.$DOMAIN + for i in $IP_ADDRS; do + echo update add $NAME.$DOMAIN $TTL A $i + done + echo +} 2>/dev/null | $NSUPDATE >/dev/null 2>&1 & + +exit 0 diff --git a/examples/smb.conf.default b/examples/smb.conf.default new file mode 100644 index 0000000..6210d69 --- /dev/null +++ b/examples/smb.conf.default @@ -0,0 +1,223 @@ +# This is the main Samba configuration file. You should read the +# smb.conf(5) manual page in order to understand the options listed +# here. Samba has a huge number of configurable options (perhaps too +# many!) most of which are not shown in this example +# +# For a step to step guide on installing, configuring and using samba, +# read the Samba-HOWTO-Collection. This may be obtained from: +# http://www.samba.org/samba/docs/Samba-HOWTO-Collection.pdf +# +# Many working examples of smb.conf files can be found in the +# Samba-Guide which is generated daily and can be downloaded from: +# http://www.samba.org/samba/docs/Samba-Guide.pdf +# +# Any line which starts with a ; (semi-colon) or a # (hash) +# is a comment and is ignored. In this example we will use a # +# for commentry and a ; for parts of the config file that you +# may wish to enable +# +# NOTE: Whenever you modify this file you should run the command "testparm" +# to check that you have not made any basic syntactic errors. +# +#======================= Global Settings ===================================== +[global] + +# workgroup = NT-Domain-Name or Workgroup-Name, eg: MIDEARTH + workgroup = MYGROUP + +# server string is the equivalent of the NT Description field + server string = Samba Server + +# Server role. Defines in which mode Samba will operate. Possible +# values are "standalone server", "member server", "classic primary +# domain controller", "classic backup domain controller", "active +# directory domain controller". +# +# Most people will want "standalone server" or "member server". +# Running as "active directory domain controller" will require first +# running "samba-tool domain provision" to wipe databases and create a +# new domain. + server role = standalone server + +# This option is important for security. It allows you to restrict +# connections to machines which are on your local network. The +# following example restricts access to two C class networks and +# the "loopback" interface. For more examples of the syntax see +# the smb.conf man page +; hosts allow = 192.168.1. 192.168.2. 127. + +# Uncomment this if you want a guest account, you must add this to /etc/passwd +# otherwise the user "nobody" is used +; guest account = pcguest + +# this tells Samba to use a separate log file for each machine +# that connects + log file = /usr/local/samba/var/log.%m + +# Put a capping on the size of the log files (in Kb). + max log size = 50 + +# Specifies the Kerberos or Active Directory realm the host is part of +; realm = MY_REALM + +# Backend to store user information in. New installations should +# use either tdbsam or ldapsam. smbpasswd is available for backwards +# compatibility. tdbsam requires no further configuration. +; passdb backend = tdbsam + +# Using the following line enables you to customise your configuration +# on a per machine basis. The %m gets replaced with the netbios name +# of the machine that is connecting. +# Note: Consider carefully the location in the configuration file of +# this line. The included file is read at that point. +; include = /usr/local/samba/lib/smb.conf.%m + +# Configure Samba to use multiple interfaces +# If you have multiple network interfaces then you must list them +# here. See the man page for details. +; interfaces = 192.168.12.2/24 192.168.13.2/24 + +# Where to store roving profiles (only for Win95 and WinNT) +# %L substitutes for this servers netbios name, %U is username +# You must uncomment the [Profiles] share below +; logon path = \\%L\Profiles\%U + +# Windows Internet Name Serving Support Section: +# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server +; wins support = yes + +# WINS Server - Tells the NMBD components of Samba to be a WINS Client +# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both +; wins server = w.x.y.z + +# WINS Proxy - Tells Samba to answer name resolution queries on +# behalf of a non WINS capable client, for this to work there must be +# at least one WINS Server on the network. The default is NO. +; wins proxy = yes + +# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names +# via DNS nslookups. The default is NO. + dns proxy = no + +# These scripts are used on a domain controller or stand-alone +# machine to add or delete corresponding unix accounts +; add user script = /usr/sbin/useradd %u +; add group script = /usr/sbin/groupadd %g +; add machine script = /usr/sbin/adduser -n -g machines -c Machine -d /dev/null -s /bin/false %u +; delete user script = /usr/sbin/userdel %u +; delete user from group script = /usr/sbin/deluser %u %g +; delete group script = /usr/sbin/groupdel %g + + +#============================ Share Definitions ============================== +[homes] + comment = Home Directories + browsable = no + writable = yes + +# Un-comment the following and create the netlogon directory for Domain Logons +; [netlogon] +; comment = Network Logon Service +; path = /usr/local/samba/lib/netlogon +; guest ok = yes +; writable = no +; share modes = no + + +# Un-comment the following to provide a specific roving profile share +# the default is to use the user's home directory +;[Profiles] +; path = /usr/local/samba/profiles +; browsable = no +; guest ok = yes + + +# NOTE: If you have a BSD-style print system there is no need to +# specifically define each individual printer +[printers] + comment = All Printers + path = /usr/spool/samba + browsable = no +# Change 'guest ok' from 'no' to 'yes' to allow the 'guest account' user to print + guest ok = no + writable = no + printable = yes + +# This one is useful for people to share files +;[tmp] +; comment = Temporary file space +; path = /tmp +; read only = no +; public = yes + +# A publicly accessible directory, but read only, except for people in +# the "staff" group +;[public] +; comment = Public Stuff +; path = /home/samba +; public = yes +; writable = no +; printable = no +; write list = @staff + +# Other examples. +# +# A private printer, usable only by fred. Spool data will be placed in fred's +# home directory. Note that fred must have write access to the spool directory, +# wherever it is. +;[fredsprn] +; comment = Fred's Printer +; valid users = fred +; path = /homes/fred +; printer = freds_printer +; public = no +; writable = no +; printable = yes + +# A private directory, usable only by fred. Note that fred requires write +# access to the directory. +;[fredsdir] +; comment = Fred's Service +; path = /usr/somewhere/private +; valid users = fred +; public = no +; writable = yes +; printable = no + +# a service which has a different directory for each machine that connects +# this allows you to tailor configurations to incoming machines. You could +# also use the %U option to tailor it by user name. +# The %m gets replaced with the machine name that is connecting. +;[pchome] +; comment = PC Directories +; path = /usr/pc/%m +; public = no +; writable = yes + +# A publicly accessible directory, read/write to all users. Note that all files +# created in the directory by users will be owned by the default user, so +# any user with access can delete any other user's files. Obviously this +# directory must be writable by the default user. Another user could of course +# be specified, in which case all files would be owned by that user instead. +;[public] +; path = /usr/somewhere/else/public +; public = yes +; only guest = yes +; writable = yes +; printable = no + +# The following two entries demonstrate how to share a directory so that two +# users can place files there that will be owned by the specific users. In this +# setup, the directory should be writable by both users and should have the +# sticky bit set on it to prevent abuse. Obviously this could be extended to +# as many users as required. +;[myshare] +; comment = Mary's and Fred's stuff +; path = /usr/somewhere/shared +; valid users = mary fred +; public = no +; writable = yes +; printable = no +; create mask = 0765 + + diff --git a/examples/systemtap/gencache.stp b/examples/systemtap/gencache.stp new file mode 100755 index 0000000..95fcff3 --- /dev/null +++ b/examples/systemtap/gencache.stp @@ -0,0 +1,147 @@ +#!/usr/bin/stap +# +# Systemtap script to instrument the Samba gencache subsystem +# +# Usage: +# +# Instrument all smbd processes: +# # stap gencache.stp smbd +# +# Instrument all winbindd processes: +# # stap gencache.stp winbindd +# +# Instrument a specific smbd process: +# # stap -x PID gencache.stp smbd +# +# Instrument a specific winbindd process: +# # stap -x PID gencache.stp winbindd +# + +global running, intervals +global cache_misses, cache_hits, neg_cache_hits + +probe begin { + printf("Collecting data, press ctrl-C to stop... ") +} + +probe process(@1).library("*").function("gencache_parse") { + running["gencache_parse", tid()] = gettimeofday_us() +} + +probe process(@1).library("*").function("gencache_parse").return { + if (!(["gencache_parse", tid()] in running)) + next + + end = gettimeofday_us() + begin = running["gencache_parse", tid()] + delete running["gencache_parse", tid()] + + duration = end - begin + intervals["gencache_parse"] <<< duration + + if ($return == 0) { + cache_misses++ + } else { + cache_hits++ + } +} + +probe process(@1).library("*").function("gencache_get_data_blob_parser") { + if ($timeout == 0) { + neg_cache_hits++ + } +} + +probe process(@1).library("*").function("gencache_get_data_blob") { + running["gencache_get_data_blob", tid()] = gettimeofday_us() +} + +probe process(@1).library("*").function("gencache_get_data_blob").return { + if (!(["gencache_get_data_blob", tid()] in running)) + next + + end = gettimeofday_us() + begin = running["gencache_get_data_blob", tid()] + delete running["gencache_get_data_blob", tid()] + + duration = end - begin + intervals["gencache_get_data_blob"] <<< duration +} + +probe process(@1).library("*").function("gencache_set_data_blob") { + running["gencache_set_data_blob", tid()] = gettimeofday_us() +} + +probe process(@1).library("*").function("gencache_set_data_blob").return { + if (!(["gencache_set_data_blob", tid()] in running)) + next + + end = gettimeofday_us() + begin = running["gencache_set_data_blob", tid()] + delete running["gencache_set_data_blob", tid()] + + duration = end - begin + intervals["gencache_set_data_blob"] <<< duration +} + +probe process(@1).library("*").function("gencache_del") { + running["gencache_del", tid()] = gettimeofday_us() +} + +probe process(@1).library("*").function("gencache_del").return { + if (!(["gencache_del", tid()] in running)) + next + + end = gettimeofday_us() + begin = running["gencache_del", tid()] + delete running["gencache_del", tid()] + + duration = end - begin + intervals["gencache_del"] <<< duration +} + +probe process(@1).library("*").function("gencache_stabilize") { + running["gencache_stabilize", tid()] = gettimeofday_us() +} + +probe process(@1).library("*").function("gencache_stabilize").return { + if (!(["gencache_stabilize", tid()] in running)) + next + + end = gettimeofday_us() + begin = running["gencache_stabilize", tid()] + delete running["gencache_stabilize", tid()] + + duration = end - begin + intervals["gencache_stabilize"] <<< duration +} + +probe end { + printf("\n\n") + + printf("Summary of cache access stats\n") + printf("=============================\n\n") + printf("%-10s %-10s %-10s\n", + "Hits", "Misses", "Negative-Hits"); + printf("--------------------------------------\n") + printf("%-10d %-10d %-10d\n", + cache_hits, cache_misses, neg_cache_hits); + + printf("\n") + + foreach ([name] in intervals) { + printf("%-30s count: %d sum: %d us (min: %d us avg: %d us max: %d us)\n", + name, + @count(intervals[name]), + @sum(intervals[name]), + @min(intervals[name]), + @avg(intervals[name]), + @max(intervals[name])) + } + + printf("\n") + foreach ([name] in intervals) { + printf("%s time distribution histogram:\n", name) + println(@hist_log(intervals[name])) + } +} diff --git a/examples/systemtap/generate-winbindd.stp.sh b/examples/systemtap/generate-winbindd.stp.sh new file mode 100755 index 0000000..3a4d2d8 --- /dev/null +++ b/examples/systemtap/generate-winbindd.stp.sh @@ -0,0 +1,310 @@ +#!/bin/sh + +outfile="$(dirname $0)/winbindd.stp" + +child_funcs="winbindd_dual_init_connection +_wbint_InitConnection +_wbint_Ping +_wbint_PamAuth +_wbint_PamAuthCrap +_wbint_PamLogOff +_wbint_PamAuthChangePassword +_wbint_PamAuthCrapChangePassword +_wbint_ListTrustedDomains +_wbint_LookupSid +_wbint_LookupSids +_wbint_LookupName +_wbint_Sids2UnixIDs +_wbint_UnixIDs2Sids +_wbint_AllocateUid +_wbint_AllocateGid +_wbint_GetNssInfo +_wbint_LookupUserAliases +_wbint_LookupUserGroups +_wbint_QuerySequenceNumber +_wbint_LookupGroupMembers +_wbint_QueryGroupList +_wbint_QueryUserRidList +_wbint_DsGetDcName +_wbint_LookupRids +_wbint_CheckMachineAccount +_wbint_ChangeMachineAccount +_wbint_PingDc" + +async_funcs="wb_ping +winbindd_lookupsid +winbindd_lookupsids +winbindd_lookupname +winbindd_sids_to_xids +winbindd_xids_to_sids +winbindd_getpwsid +winbindd_getpwnam +winbindd_getpwuid +winbindd_getsidaliases +winbindd_getuserdomgroups +winbindd_getgroups +winbindd_show_sequence +winbindd_getgrgid +winbindd_getgrnam +winbindd_getusersids +winbindd_lookuprids +winbindd_setpwent +winbindd_getpwent +winbindd_endpwent +winbindd_dsgetdcname +winbindd_getdcname +winbindd_setgrent +winbindd_getgrent +winbindd_endgrent +winbindd_list_users +winbindd_list_groups +winbindd_check_machine_acct +winbindd_ping_dc +winbindd_pam_auth +winbindd_pam_logoff +winbindd_pam_chauthtok +winbindd_pam_chng_pswd_auth_crap +winbindd_wins_byip +winbindd_wins_byname +winbindd_allocate_uid +winbindd_allocate_gid +winbindd_change_machine_acct +winbindd_pam_auth_crap" + +backend_funcs="query_user_list +enum_dom_groups +enum_local_groups +name_to_sid +sid_to_name +rids_to_names +lookup_usergroups +lookup_useraliases +lookup_groupmem +sequence_number +lockout_policy +password_policy +trusted_domains" + +header='#!/usr/bin/stap +# +# Systemtap script to instrument winbindd +# +'"# Generated by examples/systemtap/$(basename $0) on $(date), do not edit +#"' +# Usage: +# +# Instrument all winbindd processes: +# # stap winbindd.stp +# +# Instrument a specific winbindd process: +# # stap -x PID winbindd.stp +# + +global dc_running, dc_svctime +global backend_running, backend_svctime +global send_running, recv_running +global start_time, idle_time +global async_svctime, async_runtime + +probe begin { + printf("Collecting data, press ctrl-C to stop... ") +}' + +domchild_req_template=' +# +# winbind domain child function XXX +# + +probe process("winbindd").function("XXX") { + dc_running[tid(), "XXX"] = gettimeofday_us() +} + +probe process("winbindd").function("XXX").return { + if (!([tid(), "XXX"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "XXX"] + delete dc_running[tid(), "XXX"] + + duration = end - begin + dc_svctime["XXX"] <<< duration +}' + +backend_req_template=' +# +# winbind domain child backend function XXX +# + +probe process("winbindd").function("XXX@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "XXX"] = gettimeofday_us() +} + +probe process("winbindd").function("XXX@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "XXX"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "XXX"] + delete backend_running[tid(), "XXX"] + + duration = end - begin + backend_svctime["XXX"] <<< duration +}' + +async_req_template=' +# +# winbind async function XXX +# + +probe process("winbindd").function("XXX_send") { + send_running["XXX_send"] = gettimeofday_us() +} + +probe process("winbindd").function("XXX_send").return { + if (!(["XXX_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["XXX_send"] + delete send_running["XXX_send"] + + start_time["XXX_send", $return] = start + idle_time["XXX_send", $return] = end +} + +probe process("winbindd").function("XXX_recv") { + if (!(["XXX_send", $req] in start_time)) + next + + recv_running["XXX_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("XXX_recv").return { + if (!(["XXX_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["XXX_recv"] + delete recv_running["XXX_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["XXX_send", req] + delete start_time["XXX_send", req] + svctime = recv_end - send_begin + + idle = idle_time["XXX_send", req] + delete idle_time["XXX_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["XXX_send"] <<< svctime + async_runtime["XXX_send"] <<< runtime +}' + +footer=' +probe end { + printf("\n\n") + + printf("Winbind request service time\n") + printf("============================\n") + foreach ([name] in async_svctime) { + printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n", + name, + @count(async_svctime[name]), + @sum(async_svctime[name]) / 1000, + @min(async_svctime[name]), + @avg(async_svctime[name]), + @max(async_svctime[name])) + } + printf("\n") + + printf("Winbind request runtime\n") + printf("=======================\n") + foreach ([name] in async_runtime) { + printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n", + name, + @count(async_runtime[name]), + @sum(async_runtime[name]) / 1000, + @min(async_runtime[name]), + @avg(async_runtime[name]), + @max(async_runtime[name])) + } + printf("\n") + + printf("Winbind domain-child request service time\n") + printf("=========================================\n") + foreach ([name] in dc_svctime) { + printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n", + name, + @count(dc_svctime[name]), + @sum(dc_svctime[name]) / 1000, + @min(dc_svctime[name]), + @avg(dc_svctime[name]), + @max(dc_svctime[name])) + } + printf("\n") + + printf("Winbind domain-child AD-backend service time\n") + printf("============================================\n") + foreach ([name] in backend_svctime) { + printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n", + name, + @count(backend_svctime[name]), + @sum(backend_svctime[name]) / 1000, + @min(backend_svctime[name]), + @avg(backend_svctime[name]), + @max(backend_svctime[name])) + } + printf("\n") + + printf("Winbind request service time distributions (us)\n") + printf("===============================================\n") + foreach ([name] in async_svctime) { + printf("%s:\n", name); + println(@hist_log(async_svctime[name])) + } + printf("\n") + + printf("Winbind request runtime distributions (us)\n") + printf("==========================================\n") + foreach ([name] in async_runtime) { + printf("%s:\n", name); + println(@hist_log(async_runtime[name])) + } + + printf("Winbind domain-child request service time distributions (us)\n") + printf("============================================================\n") + foreach ([name] in dc_svctime) { + printf("%s:\n", name); + println(@hist_log(dc_svctime[name])) + } + + printf("Winbind domain-child AD-backend service time distributions (us)\n") + printf("===============================================================\n") + foreach ([name] in backend_svctime) { + printf("%s:\n", name); + println(@hist_log(backend_svctime[name])) + } +}' + +cat <<EOF >$outfile +$header +EOF + +printf "$child_funcs\n" | while read func; do + printf "$domchild_req_template\n" | sed -e s/XXX/$func/g >>$outfile +done + +printf "$backend_funcs\n" | while read func; do + printf "$backend_req_template\n" | sed -e "s|XXX|$func|g" >>$outfile +done + +printf "$async_funcs\n" | while read func; do + printf "$async_req_template\n" | sed -e s/XXX/$func/g >>$outfile +done + +cat <<EOF >>$outfile +$footer +EOF diff --git a/examples/systemtap/winbindd.stp b/examples/systemtap/winbindd.stp new file mode 100644 index 0000000..635784a --- /dev/null +++ b/examples/systemtap/winbindd.stp @@ -0,0 +1,2879 @@ +#!/usr/bin/stap +# +# Systemtap script to instrument winbindd +# +# Generated by examples/systemtap/generate-winbindd.stp.sh on lun 09 may 2022 17:31:44 CEST, do not edit +# +# Usage: +# +# Instrument all winbindd processes: +# # stap winbindd.stp +# +# Instrument a specific winbindd process: +# # stap -x PID winbindd.stp +# + +global dc_running, dc_svctime +global backend_running, backend_svctime +global send_running, recv_running +global start_time, idle_time +global async_svctime, async_runtime + +probe begin { + printf("Collecting data, press ctrl-C to stop... ") +} + +# +# winbind domain child function winbindd_dual_init_connection +# + +probe process("winbindd").function("winbindd_dual_init_connection") { + dc_running[tid(), "winbindd_dual_init_connection"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_dual_init_connection").return { + if (!([tid(), "winbindd_dual_init_connection"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "winbindd_dual_init_connection"] + delete dc_running[tid(), "winbindd_dual_init_connection"] + + duration = end - begin + dc_svctime["winbindd_dual_init_connection"] <<< duration +} + +# +# winbind domain child function _wbint_InitConnection +# + +probe process("winbindd").function("_wbint_InitConnection") { + dc_running[tid(), "_wbint_InitConnection"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_InitConnection").return { + if (!([tid(), "_wbint_InitConnection"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_InitConnection"] + delete dc_running[tid(), "_wbint_InitConnection"] + + duration = end - begin + dc_svctime["_wbint_InitConnection"] <<< duration +} + +# +# winbind domain child function _wbint_Ping +# + +probe process("winbindd").function("_wbint_Ping") { + dc_running[tid(), "_wbint_Ping"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_Ping").return { + if (!([tid(), "_wbint_Ping"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_Ping"] + delete dc_running[tid(), "_wbint_Ping"] + + duration = end - begin + dc_svctime["_wbint_Ping"] <<< duration +} + +# +# winbind domain child function _wbint_PamAuth +# + +probe process("winbindd").function("_wbint_PamAuth") { + dc_running[tid(), "_wbint_PamAuth"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_PamAuth").return { + if (!([tid(), "_wbint_PamAuth"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_PamAuth"] + delete dc_running[tid(), "_wbint_PamAuth"] + + duration = end - begin + dc_svctime["_wbint_PamAuth"] <<< duration +} + +# +# winbind domain child function _wbint_PamAuthCrap +# + +probe process("winbindd").function("_wbint_PamAuthCrap") { + dc_running[tid(), "_wbint_PamAuthCrap"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_PamAuthCrap").return { + if (!([tid(), "_wbint_PamAuthCrap"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_PamAuthCrap"] + delete dc_running[tid(), "_wbint_PamAuthCrap"] + + duration = end - begin + dc_svctime["_wbint_PamAuthCrap"] <<< duration +} + +# +# winbind domain child function _wbint_PamLogOff +# + +probe process("winbindd").function("_wbint_PamLogOff") { + dc_running[tid(), "_wbint_PamLogOff"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_PamLogOff").return { + if (!([tid(), "_wbint_PamLogOff"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_PamLogOff"] + delete dc_running[tid(), "_wbint_PamLogOff"] + + duration = end - begin + dc_svctime["_wbint_PamLogOff"] <<< duration +} + +# +# winbind domain child function _wbint_PamAuthChangePassword +# + +probe process("winbindd").function("_wbint_PamAuthChangePassword") { + dc_running[tid(), "_wbint_PamAuthChangePassword"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_PamAuthChangePassword").return { + if (!([tid(), "_wbint_PamAuthChangePassword"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_PamAuthChangePassword"] + delete dc_running[tid(), "_wbint_PamAuthChangePassword"] + + duration = end - begin + dc_svctime["_wbint_PamAuthChangePassword"] <<< duration +} + +# +# winbind domain child function _wbint_PamAuthCrapChangePassword +# + +probe process("winbindd").function("_wbint_PamAuthCrapChangePassword") { + dc_running[tid(), "_wbint_PamAuthCrapChangePassword"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_PamAuthCrapChangePassword").return { + if (!([tid(), "_wbint_PamAuthCrapChangePassword"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_PamAuthCrapChangePassword"] + delete dc_running[tid(), "_wbint_PamAuthCrapChangePassword"] + + duration = end - begin + dc_svctime["_wbint_PamAuthCrapChangePassword"] <<< duration +} + +# +# winbind domain child function _wbint_ListTrustedDomains +# + +probe process("winbindd").function("_wbint_ListTrustedDomains") { + dc_running[tid(), "_wbint_ListTrustedDomains"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_ListTrustedDomains").return { + if (!([tid(), "_wbint_ListTrustedDomains"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_ListTrustedDomains"] + delete dc_running[tid(), "_wbint_ListTrustedDomains"] + + duration = end - begin + dc_svctime["_wbint_ListTrustedDomains"] <<< duration +} + +# +# winbind domain child function _wbint_LookupSid +# + +probe process("winbindd").function("_wbint_LookupSid") { + dc_running[tid(), "_wbint_LookupSid"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_LookupSid").return { + if (!([tid(), "_wbint_LookupSid"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_LookupSid"] + delete dc_running[tid(), "_wbint_LookupSid"] + + duration = end - begin + dc_svctime["_wbint_LookupSid"] <<< duration +} + +# +# winbind domain child function _wbint_LookupSids +# + +probe process("winbindd").function("_wbint_LookupSids") { + dc_running[tid(), "_wbint_LookupSids"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_LookupSids").return { + if (!([tid(), "_wbint_LookupSids"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_LookupSids"] + delete dc_running[tid(), "_wbint_LookupSids"] + + duration = end - begin + dc_svctime["_wbint_LookupSids"] <<< duration +} + +# +# winbind domain child function _wbint_LookupName +# + +probe process("winbindd").function("_wbint_LookupName") { + dc_running[tid(), "_wbint_LookupName"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_LookupName").return { + if (!([tid(), "_wbint_LookupName"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_LookupName"] + delete dc_running[tid(), "_wbint_LookupName"] + + duration = end - begin + dc_svctime["_wbint_LookupName"] <<< duration +} + +# +# winbind domain child function _wbint_Sids2UnixIDs +# + +probe process("winbindd").function("_wbint_Sids2UnixIDs") { + dc_running[tid(), "_wbint_Sids2UnixIDs"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_Sids2UnixIDs").return { + if (!([tid(), "_wbint_Sids2UnixIDs"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_Sids2UnixIDs"] + delete dc_running[tid(), "_wbint_Sids2UnixIDs"] + + duration = end - begin + dc_svctime["_wbint_Sids2UnixIDs"] <<< duration +} + +# +# winbind domain child function _wbint_UnixIDs2Sids +# + +probe process("winbindd").function("_wbint_UnixIDs2Sids") { + dc_running[tid(), "_wbint_UnixIDs2Sids"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_UnixIDs2Sids").return { + if (!([tid(), "_wbint_UnixIDs2Sids"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_UnixIDs2Sids"] + delete dc_running[tid(), "_wbint_UnixIDs2Sids"] + + duration = end - begin + dc_svctime["_wbint_UnixIDs2Sids"] <<< duration +} + +# +# winbind domain child function _wbint_AllocateUid +# + +probe process("winbindd").function("_wbint_AllocateUid") { + dc_running[tid(), "_wbint_AllocateUid"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_AllocateUid").return { + if (!([tid(), "_wbint_AllocateUid"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_AllocateUid"] + delete dc_running[tid(), "_wbint_AllocateUid"] + + duration = end - begin + dc_svctime["_wbint_AllocateUid"] <<< duration +} + +# +# winbind domain child function _wbint_AllocateGid +# + +probe process("winbindd").function("_wbint_AllocateGid") { + dc_running[tid(), "_wbint_AllocateGid"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_AllocateGid").return { + if (!([tid(), "_wbint_AllocateGid"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_AllocateGid"] + delete dc_running[tid(), "_wbint_AllocateGid"] + + duration = end - begin + dc_svctime["_wbint_AllocateGid"] <<< duration +} + +# +# winbind domain child function _wbint_GetNssInfo +# + +probe process("winbindd").function("_wbint_GetNssInfo") { + dc_running[tid(), "_wbint_GetNssInfo"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_GetNssInfo").return { + if (!([tid(), "_wbint_GetNssInfo"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_GetNssInfo"] + delete dc_running[tid(), "_wbint_GetNssInfo"] + + duration = end - begin + dc_svctime["_wbint_GetNssInfo"] <<< duration +} + +# +# winbind domain child function _wbint_LookupUserAliases +# + +probe process("winbindd").function("_wbint_LookupUserAliases") { + dc_running[tid(), "_wbint_LookupUserAliases"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_LookupUserAliases").return { + if (!([tid(), "_wbint_LookupUserAliases"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_LookupUserAliases"] + delete dc_running[tid(), "_wbint_LookupUserAliases"] + + duration = end - begin + dc_svctime["_wbint_LookupUserAliases"] <<< duration +} + +# +# winbind domain child function _wbint_LookupUserGroups +# + +probe process("winbindd").function("_wbint_LookupUserGroups") { + dc_running[tid(), "_wbint_LookupUserGroups"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_LookupUserGroups").return { + if (!([tid(), "_wbint_LookupUserGroups"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_LookupUserGroups"] + delete dc_running[tid(), "_wbint_LookupUserGroups"] + + duration = end - begin + dc_svctime["_wbint_LookupUserGroups"] <<< duration +} + +# +# winbind domain child function _wbint_QuerySequenceNumber +# + +probe process("winbindd").function("_wbint_QuerySequenceNumber") { + dc_running[tid(), "_wbint_QuerySequenceNumber"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_QuerySequenceNumber").return { + if (!([tid(), "_wbint_QuerySequenceNumber"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_QuerySequenceNumber"] + delete dc_running[tid(), "_wbint_QuerySequenceNumber"] + + duration = end - begin + dc_svctime["_wbint_QuerySequenceNumber"] <<< duration +} + +# +# winbind domain child function _wbint_LookupGroupMembers +# + +probe process("winbindd").function("_wbint_LookupGroupMembers") { + dc_running[tid(), "_wbint_LookupGroupMembers"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_LookupGroupMembers").return { + if (!([tid(), "_wbint_LookupGroupMembers"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_LookupGroupMembers"] + delete dc_running[tid(), "_wbint_LookupGroupMembers"] + + duration = end - begin + dc_svctime["_wbint_LookupGroupMembers"] <<< duration +} + +# +# winbind domain child function _wbint_QueryGroupList +# + +probe process("winbindd").function("_wbint_QueryGroupList") { + dc_running[tid(), "_wbint_QueryGroupList"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_QueryGroupList").return { + if (!([tid(), "_wbint_QueryGroupList"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_QueryGroupList"] + delete dc_running[tid(), "_wbint_QueryGroupList"] + + duration = end - begin + dc_svctime["_wbint_QueryGroupList"] <<< duration +} + +# +# winbind domain child function _wbint_QueryUserRidList +# + +probe process("winbindd").function("_wbint_QueryUserRidList") { + dc_running[tid(), "_wbint_QueryUserRidList"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_QueryUserRidList").return { + if (!([tid(), "_wbint_QueryUserRidList"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_QueryUserRidList"] + delete dc_running[tid(), "_wbint_QueryUserRidList"] + + duration = end - begin + dc_svctime["_wbint_QueryUserRidList"] <<< duration +} + +# +# winbind domain child function _wbint_DsGetDcName +# + +probe process("winbindd").function("_wbint_DsGetDcName") { + dc_running[tid(), "_wbint_DsGetDcName"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_DsGetDcName").return { + if (!([tid(), "_wbint_DsGetDcName"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_DsGetDcName"] + delete dc_running[tid(), "_wbint_DsGetDcName"] + + duration = end - begin + dc_svctime["_wbint_DsGetDcName"] <<< duration +} + +# +# winbind domain child function _wbint_LookupRids +# + +probe process("winbindd").function("_wbint_LookupRids") { + dc_running[tid(), "_wbint_LookupRids"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_LookupRids").return { + if (!([tid(), "_wbint_LookupRids"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_LookupRids"] + delete dc_running[tid(), "_wbint_LookupRids"] + + duration = end - begin + dc_svctime["_wbint_LookupRids"] <<< duration +} + +# +# winbind domain child function _wbint_CheckMachineAccount +# + +probe process("winbindd").function("_wbint_CheckMachineAccount") { + dc_running[tid(), "_wbint_CheckMachineAccount"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_CheckMachineAccount").return { + if (!([tid(), "_wbint_CheckMachineAccount"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_CheckMachineAccount"] + delete dc_running[tid(), "_wbint_CheckMachineAccount"] + + duration = end - begin + dc_svctime["_wbint_CheckMachineAccount"] <<< duration +} + +# +# winbind domain child function _wbint_ChangeMachineAccount +# + +probe process("winbindd").function("_wbint_ChangeMachineAccount") { + dc_running[tid(), "_wbint_ChangeMachineAccount"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_ChangeMachineAccount").return { + if (!([tid(), "_wbint_ChangeMachineAccount"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_ChangeMachineAccount"] + delete dc_running[tid(), "_wbint_ChangeMachineAccount"] + + duration = end - begin + dc_svctime["_wbint_ChangeMachineAccount"] <<< duration +} + +# +# winbind domain child function _wbint_PingDc +# + +probe process("winbindd").function("_wbint_PingDc") { + dc_running[tid(), "_wbint_PingDc"] = gettimeofday_us() +} + +probe process("winbindd").function("_wbint_PingDc").return { + if (!([tid(), "_wbint_PingDc"] in dc_running)) + next + + end = gettimeofday_us() + begin = dc_running[tid(), "_wbint_PingDc"] + delete dc_running[tid(), "_wbint_PingDc"] + + duration = end - begin + dc_svctime["_wbint_PingDc"] <<< duration +} + +# +# winbind domain child backend function query_user_list +# + +probe process("winbindd").function("query_user_list@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "query_user_list"] = gettimeofday_us() +} + +probe process("winbindd").function("query_user_list@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "query_user_list"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "query_user_list"] + delete backend_running[tid(), "query_user_list"] + + duration = end - begin + backend_svctime["query_user_list"] <<< duration +} + +# +# winbind domain child backend function enum_dom_groups +# + +probe process("winbindd").function("enum_dom_groups@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "enum_dom_groups"] = gettimeofday_us() +} + +probe process("winbindd").function("enum_dom_groups@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "enum_dom_groups"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "enum_dom_groups"] + delete backend_running[tid(), "enum_dom_groups"] + + duration = end - begin + backend_svctime["enum_dom_groups"] <<< duration +} + +# +# winbind domain child backend function enum_local_groups +# + +probe process("winbindd").function("enum_local_groups@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "enum_local_groups"] = gettimeofday_us() +} + +probe process("winbindd").function("enum_local_groups@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "enum_local_groups"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "enum_local_groups"] + delete backend_running[tid(), "enum_local_groups"] + + duration = end - begin + backend_svctime["enum_local_groups"] <<< duration +} + +# +# winbind domain child backend function name_to_sid +# + +probe process("winbindd").function("name_to_sid@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "name_to_sid"] = gettimeofday_us() +} + +probe process("winbindd").function("name_to_sid@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "name_to_sid"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "name_to_sid"] + delete backend_running[tid(), "name_to_sid"] + + duration = end - begin + backend_svctime["name_to_sid"] <<< duration +} + +# +# winbind domain child backend function sid_to_name +# + +probe process("winbindd").function("sid_to_name@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "sid_to_name"] = gettimeofday_us() +} + +probe process("winbindd").function("sid_to_name@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "sid_to_name"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "sid_to_name"] + delete backend_running[tid(), "sid_to_name"] + + duration = end - begin + backend_svctime["sid_to_name"] <<< duration +} + +# +# winbind domain child backend function rids_to_names +# + +probe process("winbindd").function("rids_to_names@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "rids_to_names"] = gettimeofday_us() +} + +probe process("winbindd").function("rids_to_names@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "rids_to_names"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "rids_to_names"] + delete backend_running[tid(), "rids_to_names"] + + duration = end - begin + backend_svctime["rids_to_names"] <<< duration +} + +# +# winbind domain child backend function lookup_usergroups +# + +probe process("winbindd").function("lookup_usergroups@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "lookup_usergroups"] = gettimeofday_us() +} + +probe process("winbindd").function("lookup_usergroups@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "lookup_usergroups"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "lookup_usergroups"] + delete backend_running[tid(), "lookup_usergroups"] + + duration = end - begin + backend_svctime["lookup_usergroups"] <<< duration +} + +# +# winbind domain child backend function lookup_useraliases +# + +probe process("winbindd").function("lookup_useraliases@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "lookup_useraliases"] = gettimeofday_us() +} + +probe process("winbindd").function("lookup_useraliases@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "lookup_useraliases"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "lookup_useraliases"] + delete backend_running[tid(), "lookup_useraliases"] + + duration = end - begin + backend_svctime["lookup_useraliases"] <<< duration +} + +# +# winbind domain child backend function lookup_groupmem +# + +probe process("winbindd").function("lookup_groupmem@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "lookup_groupmem"] = gettimeofday_us() +} + +probe process("winbindd").function("lookup_groupmem@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "lookup_groupmem"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "lookup_groupmem"] + delete backend_running[tid(), "lookup_groupmem"] + + duration = end - begin + backend_svctime["lookup_groupmem"] <<< duration +} + +# +# winbind domain child backend function sequence_number +# + +probe process("winbindd").function("sequence_number@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "sequence_number"] = gettimeofday_us() +} + +probe process("winbindd").function("sequence_number@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "sequence_number"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "sequence_number"] + delete backend_running[tid(), "sequence_number"] + + duration = end - begin + backend_svctime["sequence_number"] <<< duration +} + +# +# winbind domain child backend function lockout_policy +# + +probe process("winbindd").function("lockout_policy@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "lockout_policy"] = gettimeofday_us() +} + +probe process("winbindd").function("lockout_policy@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "lockout_policy"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "lockout_policy"] + delete backend_running[tid(), "lockout_policy"] + + duration = end - begin + backend_svctime["lockout_policy"] <<< duration +} + +# +# winbind domain child backend function password_policy +# + +probe process("winbindd").function("password_policy@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "password_policy"] = gettimeofday_us() +} + +probe process("winbindd").function("password_policy@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "password_policy"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "password_policy"] + delete backend_running[tid(), "password_policy"] + + duration = end - begin + backend_svctime["password_policy"] <<< duration +} + +# +# winbind domain child backend function trusted_domains +# + +probe process("winbindd").function("trusted_domains@../source3/winbindd/winbindd_ads.c") { + backend_running[tid(), "trusted_domains"] = gettimeofday_us() +} + +probe process("winbindd").function("trusted_domains@../source3/winbindd/winbindd_ads.c").return { + if (!([tid(), "trusted_domains"] in backend_running)) + next + + end = gettimeofday_us() + begin = backend_running[tid(), "trusted_domains"] + delete backend_running[tid(), "trusted_domains"] + + duration = end - begin + backend_svctime["trusted_domains"] <<< duration +} + +# +# winbind async function wb_ping +# + +probe process("winbindd").function("wb_ping_send") { + send_running["wb_ping_send"] = gettimeofday_us() +} + +probe process("winbindd").function("wb_ping_send").return { + if (!(["wb_ping_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["wb_ping_send"] + delete send_running["wb_ping_send"] + + start_time["wb_ping_send", $return] = start + idle_time["wb_ping_send", $return] = end +} + +probe process("winbindd").function("wb_ping_recv") { + if (!(["wb_ping_send", $req] in start_time)) + next + + recv_running["wb_ping_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("wb_ping_recv").return { + if (!(["wb_ping_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["wb_ping_recv"] + delete recv_running["wb_ping_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["wb_ping_send", req] + delete start_time["wb_ping_send", req] + svctime = recv_end - send_begin + + idle = idle_time["wb_ping_send", req] + delete idle_time["wb_ping_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["wb_ping_send"] <<< svctime + async_runtime["wb_ping_send"] <<< runtime +} + +# +# winbind async function winbindd_lookupsid +# + +probe process("winbindd").function("winbindd_lookupsid_send") { + send_running["winbindd_lookupsid_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_lookupsid_send").return { + if (!(["winbindd_lookupsid_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_lookupsid_send"] + delete send_running["winbindd_lookupsid_send"] + + start_time["winbindd_lookupsid_send", $return] = start + idle_time["winbindd_lookupsid_send", $return] = end +} + +probe process("winbindd").function("winbindd_lookupsid_recv") { + if (!(["winbindd_lookupsid_send", $req] in start_time)) + next + + recv_running["winbindd_lookupsid_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_lookupsid_recv").return { + if (!(["winbindd_lookupsid_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_lookupsid_recv"] + delete recv_running["winbindd_lookupsid_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_lookupsid_send", req] + delete start_time["winbindd_lookupsid_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_lookupsid_send", req] + delete idle_time["winbindd_lookupsid_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_lookupsid_send"] <<< svctime + async_runtime["winbindd_lookupsid_send"] <<< runtime +} + +# +# winbind async function winbindd_lookupsids +# + +probe process("winbindd").function("winbindd_lookupsids_send") { + send_running["winbindd_lookupsids_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_lookupsids_send").return { + if (!(["winbindd_lookupsids_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_lookupsids_send"] + delete send_running["winbindd_lookupsids_send"] + + start_time["winbindd_lookupsids_send", $return] = start + idle_time["winbindd_lookupsids_send", $return] = end +} + +probe process("winbindd").function("winbindd_lookupsids_recv") { + if (!(["winbindd_lookupsids_send", $req] in start_time)) + next + + recv_running["winbindd_lookupsids_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_lookupsids_recv").return { + if (!(["winbindd_lookupsids_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_lookupsids_recv"] + delete recv_running["winbindd_lookupsids_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_lookupsids_send", req] + delete start_time["winbindd_lookupsids_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_lookupsids_send", req] + delete idle_time["winbindd_lookupsids_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_lookupsids_send"] <<< svctime + async_runtime["winbindd_lookupsids_send"] <<< runtime +} + +# +# winbind async function winbindd_lookupname +# + +probe process("winbindd").function("winbindd_lookupname_send") { + send_running["winbindd_lookupname_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_lookupname_send").return { + if (!(["winbindd_lookupname_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_lookupname_send"] + delete send_running["winbindd_lookupname_send"] + + start_time["winbindd_lookupname_send", $return] = start + idle_time["winbindd_lookupname_send", $return] = end +} + +probe process("winbindd").function("winbindd_lookupname_recv") { + if (!(["winbindd_lookupname_send", $req] in start_time)) + next + + recv_running["winbindd_lookupname_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_lookupname_recv").return { + if (!(["winbindd_lookupname_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_lookupname_recv"] + delete recv_running["winbindd_lookupname_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_lookupname_send", req] + delete start_time["winbindd_lookupname_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_lookupname_send", req] + delete idle_time["winbindd_lookupname_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_lookupname_send"] <<< svctime + async_runtime["winbindd_lookupname_send"] <<< runtime +} + +# +# winbind async function winbindd_sids_to_xids +# + +probe process("winbindd").function("winbindd_sids_to_xids_send") { + send_running["winbindd_sids_to_xids_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_sids_to_xids_send").return { + if (!(["winbindd_sids_to_xids_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_sids_to_xids_send"] + delete send_running["winbindd_sids_to_xids_send"] + + start_time["winbindd_sids_to_xids_send", $return] = start + idle_time["winbindd_sids_to_xids_send", $return] = end +} + +probe process("winbindd").function("winbindd_sids_to_xids_recv") { + if (!(["winbindd_sids_to_xids_send", $req] in start_time)) + next + + recv_running["winbindd_sids_to_xids_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_sids_to_xids_recv").return { + if (!(["winbindd_sids_to_xids_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_sids_to_xids_recv"] + delete recv_running["winbindd_sids_to_xids_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_sids_to_xids_send", req] + delete start_time["winbindd_sids_to_xids_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_sids_to_xids_send", req] + delete idle_time["winbindd_sids_to_xids_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_sids_to_xids_send"] <<< svctime + async_runtime["winbindd_sids_to_xids_send"] <<< runtime +} + +# +# winbind async function winbindd_xids_to_sids +# + +probe process("winbindd").function("winbindd_xids_to_sids_send") { + send_running["winbindd_xids_to_sids_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_xids_to_sids_send").return { + if (!(["winbindd_xids_to_sids_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_xids_to_sids_send"] + delete send_running["winbindd_xids_to_sids_send"] + + start_time["winbindd_xids_to_sids_send", $return] = start + idle_time["winbindd_xids_to_sids_send", $return] = end +} + +probe process("winbindd").function("winbindd_xids_to_sids_recv") { + if (!(["winbindd_xids_to_sids_send", $req] in start_time)) + next + + recv_running["winbindd_xids_to_sids_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_xids_to_sids_recv").return { + if (!(["winbindd_xids_to_sids_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_xids_to_sids_recv"] + delete recv_running["winbindd_xids_to_sids_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_xids_to_sids_send", req] + delete start_time["winbindd_xids_to_sids_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_xids_to_sids_send", req] + delete idle_time["winbindd_xids_to_sids_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_xids_to_sids_send"] <<< svctime + async_runtime["winbindd_xids_to_sids_send"] <<< runtime +} + +# +# winbind async function winbindd_getpwsid +# + +probe process("winbindd").function("winbindd_getpwsid_send") { + send_running["winbindd_getpwsid_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getpwsid_send").return { + if (!(["winbindd_getpwsid_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getpwsid_send"] + delete send_running["winbindd_getpwsid_send"] + + start_time["winbindd_getpwsid_send", $return] = start + idle_time["winbindd_getpwsid_send", $return] = end +} + +probe process("winbindd").function("winbindd_getpwsid_recv") { + if (!(["winbindd_getpwsid_send", $req] in start_time)) + next + + recv_running["winbindd_getpwsid_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getpwsid_recv").return { + if (!(["winbindd_getpwsid_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getpwsid_recv"] + delete recv_running["winbindd_getpwsid_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getpwsid_send", req] + delete start_time["winbindd_getpwsid_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getpwsid_send", req] + delete idle_time["winbindd_getpwsid_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getpwsid_send"] <<< svctime + async_runtime["winbindd_getpwsid_send"] <<< runtime +} + +# +# winbind async function winbindd_getpwnam +# + +probe process("winbindd").function("winbindd_getpwnam_send") { + send_running["winbindd_getpwnam_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getpwnam_send").return { + if (!(["winbindd_getpwnam_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getpwnam_send"] + delete send_running["winbindd_getpwnam_send"] + + start_time["winbindd_getpwnam_send", $return] = start + idle_time["winbindd_getpwnam_send", $return] = end +} + +probe process("winbindd").function("winbindd_getpwnam_recv") { + if (!(["winbindd_getpwnam_send", $req] in start_time)) + next + + recv_running["winbindd_getpwnam_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getpwnam_recv").return { + if (!(["winbindd_getpwnam_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getpwnam_recv"] + delete recv_running["winbindd_getpwnam_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getpwnam_send", req] + delete start_time["winbindd_getpwnam_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getpwnam_send", req] + delete idle_time["winbindd_getpwnam_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getpwnam_send"] <<< svctime + async_runtime["winbindd_getpwnam_send"] <<< runtime +} + +# +# winbind async function winbindd_getpwuid +# + +probe process("winbindd").function("winbindd_getpwuid_send") { + send_running["winbindd_getpwuid_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getpwuid_send").return { + if (!(["winbindd_getpwuid_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getpwuid_send"] + delete send_running["winbindd_getpwuid_send"] + + start_time["winbindd_getpwuid_send", $return] = start + idle_time["winbindd_getpwuid_send", $return] = end +} + +probe process("winbindd").function("winbindd_getpwuid_recv") { + if (!(["winbindd_getpwuid_send", $req] in start_time)) + next + + recv_running["winbindd_getpwuid_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getpwuid_recv").return { + if (!(["winbindd_getpwuid_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getpwuid_recv"] + delete recv_running["winbindd_getpwuid_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getpwuid_send", req] + delete start_time["winbindd_getpwuid_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getpwuid_send", req] + delete idle_time["winbindd_getpwuid_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getpwuid_send"] <<< svctime + async_runtime["winbindd_getpwuid_send"] <<< runtime +} + +# +# winbind async function winbindd_getsidaliases +# + +probe process("winbindd").function("winbindd_getsidaliases_send") { + send_running["winbindd_getsidaliases_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getsidaliases_send").return { + if (!(["winbindd_getsidaliases_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getsidaliases_send"] + delete send_running["winbindd_getsidaliases_send"] + + start_time["winbindd_getsidaliases_send", $return] = start + idle_time["winbindd_getsidaliases_send", $return] = end +} + +probe process("winbindd").function("winbindd_getsidaliases_recv") { + if (!(["winbindd_getsidaliases_send", $req] in start_time)) + next + + recv_running["winbindd_getsidaliases_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getsidaliases_recv").return { + if (!(["winbindd_getsidaliases_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getsidaliases_recv"] + delete recv_running["winbindd_getsidaliases_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getsidaliases_send", req] + delete start_time["winbindd_getsidaliases_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getsidaliases_send", req] + delete idle_time["winbindd_getsidaliases_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getsidaliases_send"] <<< svctime + async_runtime["winbindd_getsidaliases_send"] <<< runtime +} + +# +# winbind async function winbindd_getuserdomgroups +# + +probe process("winbindd").function("winbindd_getuserdomgroups_send") { + send_running["winbindd_getuserdomgroups_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getuserdomgroups_send").return { + if (!(["winbindd_getuserdomgroups_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getuserdomgroups_send"] + delete send_running["winbindd_getuserdomgroups_send"] + + start_time["winbindd_getuserdomgroups_send", $return] = start + idle_time["winbindd_getuserdomgroups_send", $return] = end +} + +probe process("winbindd").function("winbindd_getuserdomgroups_recv") { + if (!(["winbindd_getuserdomgroups_send", $req] in start_time)) + next + + recv_running["winbindd_getuserdomgroups_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getuserdomgroups_recv").return { + if (!(["winbindd_getuserdomgroups_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getuserdomgroups_recv"] + delete recv_running["winbindd_getuserdomgroups_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getuserdomgroups_send", req] + delete start_time["winbindd_getuserdomgroups_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getuserdomgroups_send", req] + delete idle_time["winbindd_getuserdomgroups_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getuserdomgroups_send"] <<< svctime + async_runtime["winbindd_getuserdomgroups_send"] <<< runtime +} + +# +# winbind async function winbindd_getgroups +# + +probe process("winbindd").function("winbindd_getgroups_send") { + send_running["winbindd_getgroups_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getgroups_send").return { + if (!(["winbindd_getgroups_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getgroups_send"] + delete send_running["winbindd_getgroups_send"] + + start_time["winbindd_getgroups_send", $return] = start + idle_time["winbindd_getgroups_send", $return] = end +} + +probe process("winbindd").function("winbindd_getgroups_recv") { + if (!(["winbindd_getgroups_send", $req] in start_time)) + next + + recv_running["winbindd_getgroups_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getgroups_recv").return { + if (!(["winbindd_getgroups_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getgroups_recv"] + delete recv_running["winbindd_getgroups_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getgroups_send", req] + delete start_time["winbindd_getgroups_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getgroups_send", req] + delete idle_time["winbindd_getgroups_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getgroups_send"] <<< svctime + async_runtime["winbindd_getgroups_send"] <<< runtime +} + +# +# winbind async function winbindd_show_sequence +# + +probe process("winbindd").function("winbindd_show_sequence_send") { + send_running["winbindd_show_sequence_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_show_sequence_send").return { + if (!(["winbindd_show_sequence_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_show_sequence_send"] + delete send_running["winbindd_show_sequence_send"] + + start_time["winbindd_show_sequence_send", $return] = start + idle_time["winbindd_show_sequence_send", $return] = end +} + +probe process("winbindd").function("winbindd_show_sequence_recv") { + if (!(["winbindd_show_sequence_send", $req] in start_time)) + next + + recv_running["winbindd_show_sequence_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_show_sequence_recv").return { + if (!(["winbindd_show_sequence_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_show_sequence_recv"] + delete recv_running["winbindd_show_sequence_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_show_sequence_send", req] + delete start_time["winbindd_show_sequence_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_show_sequence_send", req] + delete idle_time["winbindd_show_sequence_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_show_sequence_send"] <<< svctime + async_runtime["winbindd_show_sequence_send"] <<< runtime +} + +# +# winbind async function winbindd_getgrgid +# + +probe process("winbindd").function("winbindd_getgrgid_send") { + send_running["winbindd_getgrgid_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getgrgid_send").return { + if (!(["winbindd_getgrgid_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getgrgid_send"] + delete send_running["winbindd_getgrgid_send"] + + start_time["winbindd_getgrgid_send", $return] = start + idle_time["winbindd_getgrgid_send", $return] = end +} + +probe process("winbindd").function("winbindd_getgrgid_recv") { + if (!(["winbindd_getgrgid_send", $req] in start_time)) + next + + recv_running["winbindd_getgrgid_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getgrgid_recv").return { + if (!(["winbindd_getgrgid_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getgrgid_recv"] + delete recv_running["winbindd_getgrgid_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getgrgid_send", req] + delete start_time["winbindd_getgrgid_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getgrgid_send", req] + delete idle_time["winbindd_getgrgid_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getgrgid_send"] <<< svctime + async_runtime["winbindd_getgrgid_send"] <<< runtime +} + +# +# winbind async function winbindd_getgrnam +# + +probe process("winbindd").function("winbindd_getgrnam_send") { + send_running["winbindd_getgrnam_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getgrnam_send").return { + if (!(["winbindd_getgrnam_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getgrnam_send"] + delete send_running["winbindd_getgrnam_send"] + + start_time["winbindd_getgrnam_send", $return] = start + idle_time["winbindd_getgrnam_send", $return] = end +} + +probe process("winbindd").function("winbindd_getgrnam_recv") { + if (!(["winbindd_getgrnam_send", $req] in start_time)) + next + + recv_running["winbindd_getgrnam_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getgrnam_recv").return { + if (!(["winbindd_getgrnam_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getgrnam_recv"] + delete recv_running["winbindd_getgrnam_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getgrnam_send", req] + delete start_time["winbindd_getgrnam_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getgrnam_send", req] + delete idle_time["winbindd_getgrnam_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getgrnam_send"] <<< svctime + async_runtime["winbindd_getgrnam_send"] <<< runtime +} + +# +# winbind async function winbindd_getusersids +# + +probe process("winbindd").function("winbindd_getusersids_send") { + send_running["winbindd_getusersids_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getusersids_send").return { + if (!(["winbindd_getusersids_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getusersids_send"] + delete send_running["winbindd_getusersids_send"] + + start_time["winbindd_getusersids_send", $return] = start + idle_time["winbindd_getusersids_send", $return] = end +} + +probe process("winbindd").function("winbindd_getusersids_recv") { + if (!(["winbindd_getusersids_send", $req] in start_time)) + next + + recv_running["winbindd_getusersids_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getusersids_recv").return { + if (!(["winbindd_getusersids_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getusersids_recv"] + delete recv_running["winbindd_getusersids_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getusersids_send", req] + delete start_time["winbindd_getusersids_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getusersids_send", req] + delete idle_time["winbindd_getusersids_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getusersids_send"] <<< svctime + async_runtime["winbindd_getusersids_send"] <<< runtime +} + +# +# winbind async function winbindd_lookuprids +# + +probe process("winbindd").function("winbindd_lookuprids_send") { + send_running["winbindd_lookuprids_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_lookuprids_send").return { + if (!(["winbindd_lookuprids_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_lookuprids_send"] + delete send_running["winbindd_lookuprids_send"] + + start_time["winbindd_lookuprids_send", $return] = start + idle_time["winbindd_lookuprids_send", $return] = end +} + +probe process("winbindd").function("winbindd_lookuprids_recv") { + if (!(["winbindd_lookuprids_send", $req] in start_time)) + next + + recv_running["winbindd_lookuprids_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_lookuprids_recv").return { + if (!(["winbindd_lookuprids_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_lookuprids_recv"] + delete recv_running["winbindd_lookuprids_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_lookuprids_send", req] + delete start_time["winbindd_lookuprids_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_lookuprids_send", req] + delete idle_time["winbindd_lookuprids_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_lookuprids_send"] <<< svctime + async_runtime["winbindd_lookuprids_send"] <<< runtime +} + +# +# winbind async function winbindd_setpwent +# + +probe process("winbindd").function("winbindd_setpwent_send") { + send_running["winbindd_setpwent_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_setpwent_send").return { + if (!(["winbindd_setpwent_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_setpwent_send"] + delete send_running["winbindd_setpwent_send"] + + start_time["winbindd_setpwent_send", $return] = start + idle_time["winbindd_setpwent_send", $return] = end +} + +probe process("winbindd").function("winbindd_setpwent_recv") { + if (!(["winbindd_setpwent_send", $req] in start_time)) + next + + recv_running["winbindd_setpwent_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_setpwent_recv").return { + if (!(["winbindd_setpwent_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_setpwent_recv"] + delete recv_running["winbindd_setpwent_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_setpwent_send", req] + delete start_time["winbindd_setpwent_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_setpwent_send", req] + delete idle_time["winbindd_setpwent_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_setpwent_send"] <<< svctime + async_runtime["winbindd_setpwent_send"] <<< runtime +} + +# +# winbind async function winbindd_getpwent +# + +probe process("winbindd").function("winbindd_getpwent_send") { + send_running["winbindd_getpwent_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getpwent_send").return { + if (!(["winbindd_getpwent_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getpwent_send"] + delete send_running["winbindd_getpwent_send"] + + start_time["winbindd_getpwent_send", $return] = start + idle_time["winbindd_getpwent_send", $return] = end +} + +probe process("winbindd").function("winbindd_getpwent_recv") { + if (!(["winbindd_getpwent_send", $req] in start_time)) + next + + recv_running["winbindd_getpwent_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getpwent_recv").return { + if (!(["winbindd_getpwent_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getpwent_recv"] + delete recv_running["winbindd_getpwent_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getpwent_send", req] + delete start_time["winbindd_getpwent_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getpwent_send", req] + delete idle_time["winbindd_getpwent_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getpwent_send"] <<< svctime + async_runtime["winbindd_getpwent_send"] <<< runtime +} + +# +# winbind async function winbindd_endpwent +# + +probe process("winbindd").function("winbindd_endpwent_send") { + send_running["winbindd_endpwent_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_endpwent_send").return { + if (!(["winbindd_endpwent_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_endpwent_send"] + delete send_running["winbindd_endpwent_send"] + + start_time["winbindd_endpwent_send", $return] = start + idle_time["winbindd_endpwent_send", $return] = end +} + +probe process("winbindd").function("winbindd_endpwent_recv") { + if (!(["winbindd_endpwent_send", $req] in start_time)) + next + + recv_running["winbindd_endpwent_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_endpwent_recv").return { + if (!(["winbindd_endpwent_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_endpwent_recv"] + delete recv_running["winbindd_endpwent_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_endpwent_send", req] + delete start_time["winbindd_endpwent_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_endpwent_send", req] + delete idle_time["winbindd_endpwent_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_endpwent_send"] <<< svctime + async_runtime["winbindd_endpwent_send"] <<< runtime +} + +# +# winbind async function winbindd_dsgetdcname +# + +probe process("winbindd").function("winbindd_dsgetdcname_send") { + send_running["winbindd_dsgetdcname_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_dsgetdcname_send").return { + if (!(["winbindd_dsgetdcname_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_dsgetdcname_send"] + delete send_running["winbindd_dsgetdcname_send"] + + start_time["winbindd_dsgetdcname_send", $return] = start + idle_time["winbindd_dsgetdcname_send", $return] = end +} + +probe process("winbindd").function("winbindd_dsgetdcname_recv") { + if (!(["winbindd_dsgetdcname_send", $req] in start_time)) + next + + recv_running["winbindd_dsgetdcname_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_dsgetdcname_recv").return { + if (!(["winbindd_dsgetdcname_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_dsgetdcname_recv"] + delete recv_running["winbindd_dsgetdcname_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_dsgetdcname_send", req] + delete start_time["winbindd_dsgetdcname_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_dsgetdcname_send", req] + delete idle_time["winbindd_dsgetdcname_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_dsgetdcname_send"] <<< svctime + async_runtime["winbindd_dsgetdcname_send"] <<< runtime +} + +# +# winbind async function winbindd_getdcname +# + +probe process("winbindd").function("winbindd_getdcname_send") { + send_running["winbindd_getdcname_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getdcname_send").return { + if (!(["winbindd_getdcname_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getdcname_send"] + delete send_running["winbindd_getdcname_send"] + + start_time["winbindd_getdcname_send", $return] = start + idle_time["winbindd_getdcname_send", $return] = end +} + +probe process("winbindd").function("winbindd_getdcname_recv") { + if (!(["winbindd_getdcname_send", $req] in start_time)) + next + + recv_running["winbindd_getdcname_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getdcname_recv").return { + if (!(["winbindd_getdcname_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getdcname_recv"] + delete recv_running["winbindd_getdcname_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getdcname_send", req] + delete start_time["winbindd_getdcname_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getdcname_send", req] + delete idle_time["winbindd_getdcname_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getdcname_send"] <<< svctime + async_runtime["winbindd_getdcname_send"] <<< runtime +} + +# +# winbind async function winbindd_setgrent +# + +probe process("winbindd").function("winbindd_setgrent_send") { + send_running["winbindd_setgrent_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_setgrent_send").return { + if (!(["winbindd_setgrent_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_setgrent_send"] + delete send_running["winbindd_setgrent_send"] + + start_time["winbindd_setgrent_send", $return] = start + idle_time["winbindd_setgrent_send", $return] = end +} + +probe process("winbindd").function("winbindd_setgrent_recv") { + if (!(["winbindd_setgrent_send", $req] in start_time)) + next + + recv_running["winbindd_setgrent_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_setgrent_recv").return { + if (!(["winbindd_setgrent_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_setgrent_recv"] + delete recv_running["winbindd_setgrent_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_setgrent_send", req] + delete start_time["winbindd_setgrent_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_setgrent_send", req] + delete idle_time["winbindd_setgrent_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_setgrent_send"] <<< svctime + async_runtime["winbindd_setgrent_send"] <<< runtime +} + +# +# winbind async function winbindd_getgrent +# + +probe process("winbindd").function("winbindd_getgrent_send") { + send_running["winbindd_getgrent_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getgrent_send").return { + if (!(["winbindd_getgrent_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_getgrent_send"] + delete send_running["winbindd_getgrent_send"] + + start_time["winbindd_getgrent_send", $return] = start + idle_time["winbindd_getgrent_send", $return] = end +} + +probe process("winbindd").function("winbindd_getgrent_recv") { + if (!(["winbindd_getgrent_send", $req] in start_time)) + next + + recv_running["winbindd_getgrent_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_getgrent_recv").return { + if (!(["winbindd_getgrent_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_getgrent_recv"] + delete recv_running["winbindd_getgrent_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_getgrent_send", req] + delete start_time["winbindd_getgrent_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_getgrent_send", req] + delete idle_time["winbindd_getgrent_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_getgrent_send"] <<< svctime + async_runtime["winbindd_getgrent_send"] <<< runtime +} + +# +# winbind async function winbindd_endgrent +# + +probe process("winbindd").function("winbindd_endgrent_send") { + send_running["winbindd_endgrent_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_endgrent_send").return { + if (!(["winbindd_endgrent_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_endgrent_send"] + delete send_running["winbindd_endgrent_send"] + + start_time["winbindd_endgrent_send", $return] = start + idle_time["winbindd_endgrent_send", $return] = end +} + +probe process("winbindd").function("winbindd_endgrent_recv") { + if (!(["winbindd_endgrent_send", $req] in start_time)) + next + + recv_running["winbindd_endgrent_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_endgrent_recv").return { + if (!(["winbindd_endgrent_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_endgrent_recv"] + delete recv_running["winbindd_endgrent_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_endgrent_send", req] + delete start_time["winbindd_endgrent_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_endgrent_send", req] + delete idle_time["winbindd_endgrent_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_endgrent_send"] <<< svctime + async_runtime["winbindd_endgrent_send"] <<< runtime +} + +# +# winbind async function winbindd_list_users +# + +probe process("winbindd").function("winbindd_list_users_send") { + send_running["winbindd_list_users_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_list_users_send").return { + if (!(["winbindd_list_users_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_list_users_send"] + delete send_running["winbindd_list_users_send"] + + start_time["winbindd_list_users_send", $return] = start + idle_time["winbindd_list_users_send", $return] = end +} + +probe process("winbindd").function("winbindd_list_users_recv") { + if (!(["winbindd_list_users_send", $req] in start_time)) + next + + recv_running["winbindd_list_users_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_list_users_recv").return { + if (!(["winbindd_list_users_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_list_users_recv"] + delete recv_running["winbindd_list_users_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_list_users_send", req] + delete start_time["winbindd_list_users_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_list_users_send", req] + delete idle_time["winbindd_list_users_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_list_users_send"] <<< svctime + async_runtime["winbindd_list_users_send"] <<< runtime +} + +# +# winbind async function winbindd_list_groups +# + +probe process("winbindd").function("winbindd_list_groups_send") { + send_running["winbindd_list_groups_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_list_groups_send").return { + if (!(["winbindd_list_groups_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_list_groups_send"] + delete send_running["winbindd_list_groups_send"] + + start_time["winbindd_list_groups_send", $return] = start + idle_time["winbindd_list_groups_send", $return] = end +} + +probe process("winbindd").function("winbindd_list_groups_recv") { + if (!(["winbindd_list_groups_send", $req] in start_time)) + next + + recv_running["winbindd_list_groups_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_list_groups_recv").return { + if (!(["winbindd_list_groups_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_list_groups_recv"] + delete recv_running["winbindd_list_groups_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_list_groups_send", req] + delete start_time["winbindd_list_groups_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_list_groups_send", req] + delete idle_time["winbindd_list_groups_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_list_groups_send"] <<< svctime + async_runtime["winbindd_list_groups_send"] <<< runtime +} + +# +# winbind async function winbindd_check_machine_acct +# + +probe process("winbindd").function("winbindd_check_machine_acct_send") { + send_running["winbindd_check_machine_acct_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_check_machine_acct_send").return { + if (!(["winbindd_check_machine_acct_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_check_machine_acct_send"] + delete send_running["winbindd_check_machine_acct_send"] + + start_time["winbindd_check_machine_acct_send", $return] = start + idle_time["winbindd_check_machine_acct_send", $return] = end +} + +probe process("winbindd").function("winbindd_check_machine_acct_recv") { + if (!(["winbindd_check_machine_acct_send", $req] in start_time)) + next + + recv_running["winbindd_check_machine_acct_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_check_machine_acct_recv").return { + if (!(["winbindd_check_machine_acct_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_check_machine_acct_recv"] + delete recv_running["winbindd_check_machine_acct_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_check_machine_acct_send", req] + delete start_time["winbindd_check_machine_acct_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_check_machine_acct_send", req] + delete idle_time["winbindd_check_machine_acct_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_check_machine_acct_send"] <<< svctime + async_runtime["winbindd_check_machine_acct_send"] <<< runtime +} + +# +# winbind async function winbindd_ping_dc +# + +probe process("winbindd").function("winbindd_ping_dc_send") { + send_running["winbindd_ping_dc_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_ping_dc_send").return { + if (!(["winbindd_ping_dc_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_ping_dc_send"] + delete send_running["winbindd_ping_dc_send"] + + start_time["winbindd_ping_dc_send", $return] = start + idle_time["winbindd_ping_dc_send", $return] = end +} + +probe process("winbindd").function("winbindd_ping_dc_recv") { + if (!(["winbindd_ping_dc_send", $req] in start_time)) + next + + recv_running["winbindd_ping_dc_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_ping_dc_recv").return { + if (!(["winbindd_ping_dc_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_ping_dc_recv"] + delete recv_running["winbindd_ping_dc_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_ping_dc_send", req] + delete start_time["winbindd_ping_dc_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_ping_dc_send", req] + delete idle_time["winbindd_ping_dc_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_ping_dc_send"] <<< svctime + async_runtime["winbindd_ping_dc_send"] <<< runtime +} + +# +# winbind async function winbindd_pam_auth +# + +probe process("winbindd").function("winbindd_pam_auth_send") { + send_running["winbindd_pam_auth_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_auth_send").return { + if (!(["winbindd_pam_auth_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_pam_auth_send"] + delete send_running["winbindd_pam_auth_send"] + + start_time["winbindd_pam_auth_send", $return] = start + idle_time["winbindd_pam_auth_send", $return] = end +} + +probe process("winbindd").function("winbindd_pam_auth_recv") { + if (!(["winbindd_pam_auth_send", $req] in start_time)) + next + + recv_running["winbindd_pam_auth_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_auth_recv").return { + if (!(["winbindd_pam_auth_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_pam_auth_recv"] + delete recv_running["winbindd_pam_auth_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_pam_auth_send", req] + delete start_time["winbindd_pam_auth_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_pam_auth_send", req] + delete idle_time["winbindd_pam_auth_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_pam_auth_send"] <<< svctime + async_runtime["winbindd_pam_auth_send"] <<< runtime +} + +# +# winbind async function winbindd_pam_logoff +# + +probe process("winbindd").function("winbindd_pam_logoff_send") { + send_running["winbindd_pam_logoff_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_logoff_send").return { + if (!(["winbindd_pam_logoff_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_pam_logoff_send"] + delete send_running["winbindd_pam_logoff_send"] + + start_time["winbindd_pam_logoff_send", $return] = start + idle_time["winbindd_pam_logoff_send", $return] = end +} + +probe process("winbindd").function("winbindd_pam_logoff_recv") { + if (!(["winbindd_pam_logoff_send", $req] in start_time)) + next + + recv_running["winbindd_pam_logoff_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_logoff_recv").return { + if (!(["winbindd_pam_logoff_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_pam_logoff_recv"] + delete recv_running["winbindd_pam_logoff_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_pam_logoff_send", req] + delete start_time["winbindd_pam_logoff_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_pam_logoff_send", req] + delete idle_time["winbindd_pam_logoff_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_pam_logoff_send"] <<< svctime + async_runtime["winbindd_pam_logoff_send"] <<< runtime +} + +# +# winbind async function winbindd_pam_chauthtok +# + +probe process("winbindd").function("winbindd_pam_chauthtok_send") { + send_running["winbindd_pam_chauthtok_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_chauthtok_send").return { + if (!(["winbindd_pam_chauthtok_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_pam_chauthtok_send"] + delete send_running["winbindd_pam_chauthtok_send"] + + start_time["winbindd_pam_chauthtok_send", $return] = start + idle_time["winbindd_pam_chauthtok_send", $return] = end +} + +probe process("winbindd").function("winbindd_pam_chauthtok_recv") { + if (!(["winbindd_pam_chauthtok_send", $req] in start_time)) + next + + recv_running["winbindd_pam_chauthtok_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_chauthtok_recv").return { + if (!(["winbindd_pam_chauthtok_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_pam_chauthtok_recv"] + delete recv_running["winbindd_pam_chauthtok_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_pam_chauthtok_send", req] + delete start_time["winbindd_pam_chauthtok_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_pam_chauthtok_send", req] + delete idle_time["winbindd_pam_chauthtok_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_pam_chauthtok_send"] <<< svctime + async_runtime["winbindd_pam_chauthtok_send"] <<< runtime +} + +# +# winbind async function winbindd_pam_chng_pswd_auth_crap +# + +probe process("winbindd").function("winbindd_pam_chng_pswd_auth_crap_send") { + send_running["winbindd_pam_chng_pswd_auth_crap_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_chng_pswd_auth_crap_send").return { + if (!(["winbindd_pam_chng_pswd_auth_crap_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_pam_chng_pswd_auth_crap_send"] + delete send_running["winbindd_pam_chng_pswd_auth_crap_send"] + + start_time["winbindd_pam_chng_pswd_auth_crap_send", $return] = start + idle_time["winbindd_pam_chng_pswd_auth_crap_send", $return] = end +} + +probe process("winbindd").function("winbindd_pam_chng_pswd_auth_crap_recv") { + if (!(["winbindd_pam_chng_pswd_auth_crap_send", $req] in start_time)) + next + + recv_running["winbindd_pam_chng_pswd_auth_crap_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_chng_pswd_auth_crap_recv").return { + if (!(["winbindd_pam_chng_pswd_auth_crap_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_pam_chng_pswd_auth_crap_recv"] + delete recv_running["winbindd_pam_chng_pswd_auth_crap_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_pam_chng_pswd_auth_crap_send", req] + delete start_time["winbindd_pam_chng_pswd_auth_crap_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_pam_chng_pswd_auth_crap_send", req] + delete idle_time["winbindd_pam_chng_pswd_auth_crap_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_pam_chng_pswd_auth_crap_send"] <<< svctime + async_runtime["winbindd_pam_chng_pswd_auth_crap_send"] <<< runtime +} + +# +# winbind async function winbindd_wins_byip +# + +probe process("winbindd").function("winbindd_wins_byip_send") { + send_running["winbindd_wins_byip_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_wins_byip_send").return { + if (!(["winbindd_wins_byip_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_wins_byip_send"] + delete send_running["winbindd_wins_byip_send"] + + start_time["winbindd_wins_byip_send", $return] = start + idle_time["winbindd_wins_byip_send", $return] = end +} + +probe process("winbindd").function("winbindd_wins_byip_recv") { + if (!(["winbindd_wins_byip_send", $req] in start_time)) + next + + recv_running["winbindd_wins_byip_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_wins_byip_recv").return { + if (!(["winbindd_wins_byip_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_wins_byip_recv"] + delete recv_running["winbindd_wins_byip_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_wins_byip_send", req] + delete start_time["winbindd_wins_byip_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_wins_byip_send", req] + delete idle_time["winbindd_wins_byip_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_wins_byip_send"] <<< svctime + async_runtime["winbindd_wins_byip_send"] <<< runtime +} + +# +# winbind async function winbindd_wins_byname +# + +probe process("winbindd").function("winbindd_wins_byname_send") { + send_running["winbindd_wins_byname_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_wins_byname_send").return { + if (!(["winbindd_wins_byname_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_wins_byname_send"] + delete send_running["winbindd_wins_byname_send"] + + start_time["winbindd_wins_byname_send", $return] = start + idle_time["winbindd_wins_byname_send", $return] = end +} + +probe process("winbindd").function("winbindd_wins_byname_recv") { + if (!(["winbindd_wins_byname_send", $req] in start_time)) + next + + recv_running["winbindd_wins_byname_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_wins_byname_recv").return { + if (!(["winbindd_wins_byname_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_wins_byname_recv"] + delete recv_running["winbindd_wins_byname_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_wins_byname_send", req] + delete start_time["winbindd_wins_byname_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_wins_byname_send", req] + delete idle_time["winbindd_wins_byname_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_wins_byname_send"] <<< svctime + async_runtime["winbindd_wins_byname_send"] <<< runtime +} + +# +# winbind async function winbindd_allocate_uid +# + +probe process("winbindd").function("winbindd_allocate_uid_send") { + send_running["winbindd_allocate_uid_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_allocate_uid_send").return { + if (!(["winbindd_allocate_uid_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_allocate_uid_send"] + delete send_running["winbindd_allocate_uid_send"] + + start_time["winbindd_allocate_uid_send", $return] = start + idle_time["winbindd_allocate_uid_send", $return] = end +} + +probe process("winbindd").function("winbindd_allocate_uid_recv") { + if (!(["winbindd_allocate_uid_send", $req] in start_time)) + next + + recv_running["winbindd_allocate_uid_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_allocate_uid_recv").return { + if (!(["winbindd_allocate_uid_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_allocate_uid_recv"] + delete recv_running["winbindd_allocate_uid_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_allocate_uid_send", req] + delete start_time["winbindd_allocate_uid_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_allocate_uid_send", req] + delete idle_time["winbindd_allocate_uid_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_allocate_uid_send"] <<< svctime + async_runtime["winbindd_allocate_uid_send"] <<< runtime +} + +# +# winbind async function winbindd_allocate_gid +# + +probe process("winbindd").function("winbindd_allocate_gid_send") { + send_running["winbindd_allocate_gid_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_allocate_gid_send").return { + if (!(["winbindd_allocate_gid_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_allocate_gid_send"] + delete send_running["winbindd_allocate_gid_send"] + + start_time["winbindd_allocate_gid_send", $return] = start + idle_time["winbindd_allocate_gid_send", $return] = end +} + +probe process("winbindd").function("winbindd_allocate_gid_recv") { + if (!(["winbindd_allocate_gid_send", $req] in start_time)) + next + + recv_running["winbindd_allocate_gid_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_allocate_gid_recv").return { + if (!(["winbindd_allocate_gid_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_allocate_gid_recv"] + delete recv_running["winbindd_allocate_gid_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_allocate_gid_send", req] + delete start_time["winbindd_allocate_gid_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_allocate_gid_send", req] + delete idle_time["winbindd_allocate_gid_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_allocate_gid_send"] <<< svctime + async_runtime["winbindd_allocate_gid_send"] <<< runtime +} + +# +# winbind async function winbindd_change_machine_acct +# + +probe process("winbindd").function("winbindd_change_machine_acct_send") { + send_running["winbindd_change_machine_acct_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_change_machine_acct_send").return { + if (!(["winbindd_change_machine_acct_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_change_machine_acct_send"] + delete send_running["winbindd_change_machine_acct_send"] + + start_time["winbindd_change_machine_acct_send", $return] = start + idle_time["winbindd_change_machine_acct_send", $return] = end +} + +probe process("winbindd").function("winbindd_change_machine_acct_recv") { + if (!(["winbindd_change_machine_acct_send", $req] in start_time)) + next + + recv_running["winbindd_change_machine_acct_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_change_machine_acct_recv").return { + if (!(["winbindd_change_machine_acct_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_change_machine_acct_recv"] + delete recv_running["winbindd_change_machine_acct_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_change_machine_acct_send", req] + delete start_time["winbindd_change_machine_acct_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_change_machine_acct_send", req] + delete idle_time["winbindd_change_machine_acct_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_change_machine_acct_send"] <<< svctime + async_runtime["winbindd_change_machine_acct_send"] <<< runtime +} + +# +# winbind async function winbindd_pam_auth_crap +# + +probe process("winbindd").function("winbindd_pam_auth_crap_send") { + send_running["winbindd_pam_auth_crap_send"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_auth_crap_send").return { + if (!(["winbindd_pam_auth_crap_send"] in send_running)) + next + + end = gettimeofday_us() + start = send_running["winbindd_pam_auth_crap_send"] + delete send_running["winbindd_pam_auth_crap_send"] + + start_time["winbindd_pam_auth_crap_send", $return] = start + idle_time["winbindd_pam_auth_crap_send", $return] = end +} + +probe process("winbindd").function("winbindd_pam_auth_crap_recv") { + if (!(["winbindd_pam_auth_crap_send", $req] in start_time)) + next + + recv_running["winbindd_pam_auth_crap_recv"] = gettimeofday_us() +} + +probe process("winbindd").function("winbindd_pam_auth_crap_recv").return { + if (!(["winbindd_pam_auth_crap_recv"] in recv_running)) + next + + recv_end = gettimeofday_us() + recv_start = recv_running["winbindd_pam_auth_crap_recv"] + delete recv_running["winbindd_pam_auth_crap_recv"] + recv_runtime = recv_end - recv_start + + req = @entry($req) + + send_begin = start_time["winbindd_pam_auth_crap_send", req] + delete start_time["winbindd_pam_auth_crap_send", req] + svctime = recv_end - send_begin + + idle = idle_time["winbindd_pam_auth_crap_send", req] + delete idle_time["winbindd_pam_auth_crap_send", req] + runtime = (idle - send_begin) + recv_runtime + + async_svctime["winbindd_pam_auth_crap_send"] <<< svctime + async_runtime["winbindd_pam_auth_crap_send"] <<< runtime +} + +probe end { + printf("\n\n") + + printf("Winbind request service time\n") + printf("============================\n") + foreach ([name] in async_svctime) { + printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n", + name, + @count(async_svctime[name]), + @sum(async_svctime[name]) / 1000, + @min(async_svctime[name]), + @avg(async_svctime[name]), + @max(async_svctime[name])) + } + printf("\n") + + printf("Winbind request runtime\n") + printf("=======================\n") + foreach ([name] in async_runtime) { + printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n", + name, + @count(async_runtime[name]), + @sum(async_runtime[name]) / 1000, + @min(async_runtime[name]), + @avg(async_runtime[name]), + @max(async_runtime[name])) + } + printf("\n") + + printf("Winbind domain-child request service time\n") + printf("=========================================\n") + foreach ([name] in dc_svctime) { + printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n", + name, + @count(dc_svctime[name]), + @sum(dc_svctime[name]) / 1000, + @min(dc_svctime[name]), + @avg(dc_svctime[name]), + @max(dc_svctime[name])) + } + printf("\n") + + printf("Winbind domain-child AD-backend service time\n") + printf("============================================\n") + foreach ([name] in backend_svctime) { + printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n", + name, + @count(backend_svctime[name]), + @sum(backend_svctime[name]) / 1000, + @min(backend_svctime[name]), + @avg(backend_svctime[name]), + @max(backend_svctime[name])) + } + printf("\n") + + printf("Winbind request service time distributions (us)\n") + printf("===============================================\n") + foreach ([name] in async_svctime) { + printf("%s:\n", name); + println(@hist_log(async_svctime[name])) + } + printf("\n") + + printf("Winbind request runtime distributions (us)\n") + printf("==========================================\n") + foreach ([name] in async_runtime) { + printf("%s:\n", name); + println(@hist_log(async_runtime[name])) + } + + printf("Winbind domain-child request service time distributions (us)\n") + printf("============================================================\n") + foreach ([name] in dc_svctime) { + printf("%s:\n", name); + println(@hist_log(dc_svctime[name])) + } + + printf("Winbind domain-child AD-backend service time distributions (us)\n") + printf("===============================================================\n") + foreach ([name] in backend_svctime) { + printf("%s:\n", name); + println(@hist_log(backend_svctime[name])) + } +} diff --git a/examples/winexe/README b/examples/winexe/README new file mode 100644 index 0000000..c688e5d --- /dev/null +++ b/examples/winexe/README @@ -0,0 +1,18 @@ +winexe from https://sourceforge.net/projects/winexe/ is a project +based on Samba libraries from 2012. According to the winexe git +repository the last Samba commit winexe was updated to is 47bbf9886f0c +from November 6, 2012. As winexe uses unpublished Samba internal +libraries, it broke over time. + +This is a port of the winexe functionality to more modern Samba +versions. It still uses internal APIs, but it being part of the tree +means that it is much easier to keep up to date. + +The Windows service files were taken literally from the original +winexe from the sourceforge git. Andrzej Hajda chose GPLv3 only and +not GPLv3+. As GPL evolves very slowly, this should not be a practical +problem for quite some time. + +To build it under Linux, you need mingw binaries on your build +system. Under Debian stretch, the package names are gcc-mingw-w64 and +friends. diff --git a/examples/winexe/winexe.c b/examples/winexe/winexe.c new file mode 100644 index 0000000..5c2529c --- /dev/null +++ b/examples/winexe/winexe.c @@ -0,0 +1,1918 @@ +/* + * Samba Unix/Linux CIFS implementation + * + * winexe + * + * Copyright (C) 2018 Volker Lendecke <vl@samba.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "version.h" +#include <popt.h> +#include <tevent.h> +#include "lib/param/param.h" +#include "auth/credentials/credentials.h" +#include "lib/util/talloc_stack.h" +#include "lib/util/tevent_ntstatus.h" +#include "lib/util/sys_rw.h" +#include "libsmb/proto.h" +#include "librpc/gen_ndr/ndr_svcctl_c.h" +#include "rpc_client/cli_pipe.h" +#include "libcli/smb/smbXcli_base.h" +#include "libcli/util/werror.h" +#include "lib/async_req/async_sock.h" +#include "lib/cmdline/cmdline.h" +#include "client.h" + +#define SVC_INTERACTIVE 1 +#define SVC_IGNORE_INTERACTIVE 2 +#define SVC_INTERACTIVE_MASK 3 +#define SVC_FORCE_UPLOAD 4 +#define SVC_OS64BIT 8 +#define SVC_OSCHOOSE 16 +#define SVC_UNINSTALL 32 +#define SVC_SYSTEM 64 + +#define SERVICE_NAME "winexesvc" + +#define PIPE_NAME "ahexec" +#define PIPE_NAME_IN "ahexec_stdin%08X" +#define PIPE_NAME_OUT "ahexec_stdout%08X" +#define PIPE_NAME_ERR "ahexec_stderr%08X" + +static const char version_message_fmt[] = "winexe version %d.%d\n" + "This program may be freely redistributed under the terms of the " + "GNU GPLv3\n"; + +struct program_options { + char *hostname; + int port; + char *cmd; + struct cli_credentials *credentials; + char *runas; + char *runas_file; + int flags; +}; + +static void parse_args(int argc, const char *argv[], + TALLOC_CTX *mem_ctx, + struct program_options *options) +{ + poptContext pc; + int opt, i; + + int argc_new; + char **argv_new; + + int port = 445; + char *port_str = NULL; + + int flag_interactive = SVC_IGNORE_INTERACTIVE; + int flag_ostype = 2; + int flag_reinstall = 0; + int flag_uninstall = 0; + int flag_help = 0; + int flag_version = 0; + bool ok; + + struct poptOption long_options[] = { + POPT_AUTOHELP + { + .longName = "uninstall", + .shortName = 0, + .argInfo = POPT_ARG_NONE, + .arg = &flag_uninstall, + .val = 0, + .descrip = "Uninstall winexe service after " + "remote execution", + .argDescrip = NULL, + },{ + .longName = "reinstall", + .shortName = 0, + .argInfo = POPT_ARG_NONE, + .arg = &flag_reinstall, + .val = 0, + .descrip = "Reinstall winexe service before " + "remote execution", + .argDescrip = NULL, + },{ + .longName = "runas", + .shortName = 0, + .argInfo = POPT_ARG_STRING, + .arg = &options->runas, + .val = 0, + .descrip = "Run as the given user (BEWARE: this " + "password is sent in cleartext over " + "the network!)", + .argDescrip = "[DOMAIN\\]USERNAME%PASSWORD", + },{ + .longName = "runas-file", + .shortName = 0, + .argInfo = POPT_ARG_STRING, + .arg = &options->runas_file, + .val = 0, + .descrip = "Run as user options defined in a file", + .argDescrip = "FILE", + },{ + .longName = "interactive", + .shortName = 0, + .argInfo = POPT_ARG_INT, + .arg = &flag_interactive, + .val = 0, + .descrip = "Desktop interaction: 0 - disallow, " + "1 - allow. If allow, also use the " + "--system switch (Windows requirement). " + "Vista does not support this option.", + .argDescrip = "0|1", + },{ + .longName = "ostype", + .shortName = 0, + .argInfo = POPT_ARG_INT, + .arg = &flag_ostype, + .val = 0, + .descrip = "OS type: 0 - 32-bit, 1 - 64-bit, " + "2 - winexe will decide. " + "Determines which version (32-bit or 64-bit)" + " of service will be installed.", + .argDescrip = "0|1|2", + }, + POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS + POPT_COMMON_VERSION + POPT_TABLEEND + }; + + ZERO_STRUCTP(options); + + ok = samba_cmdline_init(mem_ctx, + SAMBA_CMDLINE_CONFIG_CLIENT, + false /* require_smbconf */); + if (!ok) { + DBG_ERR("Failed to init cmdline parser!\n"); + TALLOC_FREE(mem_ctx); + exit(1); + } + + pc = samba_popt_get_context(getprogname(), + argc, + argv, + long_options, + 0); + if (pc == NULL) { + DBG_ERR("Failed to setup popt context!\n"); + TALLOC_FREE(mem_ctx); + exit(1); + } + + poptSetOtherOptionHelp(pc, "[OPTION]... //HOST[:PORT] COMMAND\nOptions:"); + + if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) { + fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR, + SAMBA_VERSION_MINOR); + if (flag_version) { + exit(0); + } + poptPrintHelp(pc, stdout, 0); + if (flag_help) { + exit(0); + } + exit(1); + } + + argv_new = discard_const_p(char *, poptGetArgs(pc)); + + argc_new = argc; + for (i = 0; i < argc; i++) { + if (!argv_new || argv_new[i] == NULL) { + argc_new = i; + break; + } + } + + if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') { + fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR, + SAMBA_VERSION_MINOR); + poptPrintHelp(pc, stdout, 0); + exit(1); + } + + port_str = strchr(argv_new[0], ':'); + if (port_str) { + if (sscanf(port_str + 1, "%d", &port) != 1 || port <= 0) { + fprintf(stderr, version_message_fmt, + SAMBA_VERSION_MAJOR, SAMBA_VERSION_MINOR); + poptPrintHelp(pc, stdout, 0); + exit(1); + } + *port_str = '\0'; + } + + if (options->runas == NULL && options->runas_file != NULL) { + struct cli_credentials *runas_cred; + const char *user; + const char *pass; + + runas_cred = cli_credentials_init(mem_ctx); + cli_credentials_parse_file(runas_cred, options->runas_file, + CRED_SPECIFIED); + + user = cli_credentials_get_username(runas_cred); + pass = cli_credentials_get_password(runas_cred); + + if (user && pass) { + char buffer[1024]; + const char *dom; + + dom = cli_credentials_get_domain(runas_cred); + if (dom) { + snprintf(buffer, sizeof(buffer), "%s\\%s%%%s", + dom, user, pass); + } else { + snprintf(buffer, sizeof(buffer), "%s%%%s", + user, pass); + } + buffer[sizeof(buffer)-1] = '\0'; + options->runas = talloc_strdup(mem_ctx, buffer); + } + } + + options->credentials = samba_cmdline_get_creds(); + + options->hostname = talloc_strdup(mem_ctx, argv_new[0] + 2); + if (options->hostname == NULL) { + DBG_ERR("Out of memory\n"); + exit(1); + } + options->port = port; + options->cmd = talloc_strdup(mem_ctx, argv_new[1]); + if (options->cmd == NULL) { + DBG_ERR("Out of memory\n"); + exit(1); + } + + poptFreeContext(pc); + + options->flags = flag_interactive; + if (flag_reinstall) { + options->flags |= SVC_FORCE_UPLOAD; + } + if (flag_ostype == 1) { + options->flags |= SVC_OS64BIT; + } + if (flag_ostype == 2) { + options->flags |= SVC_OSCHOOSE; + } + if (flag_uninstall) { + options->flags |= SVC_UNINSTALL; + } +} + +static NTSTATUS winexe_svc_upload( + const char *hostname, + int port, + const char *service_filename, + const DATA_BLOB *svc32_exe, + const DATA_BLOB *svc64_exe, + struct cli_credentials *credentials, + int flags) +{ + struct cli_state *cli; + uint16_t fnum = 0xffff; + NTSTATUS status; + const DATA_BLOB *binary = NULL; + + status = cli_full_connection_creds( + &cli, + NULL, + hostname, + NULL, + port, + "ADMIN$", + "?????", + credentials, + 0); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("cli_full_connection_creds failed: %s\n", + nt_errstr(status)); + return status; + } + + if (flags & SVC_FORCE_UPLOAD) { + status = cli_unlink(cli, service_filename, 0); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("cli_unlink failed: %s\n", + nt_errstr(status)); + } + } + + if (flags & SVC_OSCHOOSE) { + status = cli_chkpath(cli, "SysWoW64"); + if (NT_STATUS_IS_OK(status)) { + flags |= SVC_OS64BIT; + } + } + + if (flags & SVC_OS64BIT) { + binary = svc64_exe; + } else { + binary = svc32_exe; + } + + if (binary == NULL) { + goto done; + } + + status = cli_ntcreate( + cli, + service_filename, + 0, /* CreatFlags */ + SEC_FILE_WRITE_DATA, /* DesiredAccess */ + FILE_ATTRIBUTE_NORMAL, /* FileAttributes */ + FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */ + FILE_OPEN_IF, /* CreateDisposition */ + FILE_NON_DIRECTORY_FILE, /* CreateOptions */ + 0, /* SecurityFlags */ + &fnum, + NULL); /* CreateReturns */ + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("Could not create %s: %s\n", service_filename, + nt_errstr(status)); + goto done; + } + + status = cli_writeall( + cli, + fnum, + 0, + binary->data, + 0, + binary->length, + NULL); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("Could not write file: %s\n", nt_errstr(status)); + goto done; + } + +done: + if (fnum != 0xffff) { + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n", + fnum, + service_filename, + nt_errstr(status)); + } + } + + TALLOC_FREE(cli); + return status; +} + +static NTSTATUS winexe_svc_install( + struct cli_state *cli, + const char *hostname, + int port, + const char *service_name, + const char *service_filename, + const DATA_BLOB *svc32_exe, + const DATA_BLOB *svc64_exe, + struct cli_credentials *credentials, + int flags) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct rpc_pipe_client *rpccli; + struct policy_handle scmanager_handle; + struct policy_handle service_handle; + struct SERVICE_STATUS service_status; + bool need_start = false; + bool need_conf = false; + NTSTATUS status; + WERROR werr; + const char *remote_name = smbXcli_conn_remote_name(cli->conn); + const struct sockaddr_storage *remote_sockaddr = + smbXcli_conn_remote_sockaddr(cli->conn); + + status = cli_rpc_pipe_open_noauth_transport( + cli, + NCACN_NP, + &ndr_table_svcctl, + remote_name, + remote_sockaddr, + &rpccli); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n", + nt_errstr(status)); + goto done; + } + + status = dcerpc_svcctl_OpenSCManagerW( + rpccli->binding_handle, + frame, + remote_name, + NULL, + SEC_FLAG_MAXIMUM_ALLOWED, + &scmanager_handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n", + nt_errstr(status)); + goto done; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n", + win_errstr(werr)); + goto done; + } + + status = dcerpc_svcctl_OpenServiceW( + rpccli->binding_handle, + frame, + &scmanager_handle, + service_name, + SERVICE_ALL_ACCESS, + &service_handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n", + nt_errstr(status)); + goto close_scmanager; + } + + if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) { + status = dcerpc_svcctl_CreateServiceW( + rpccli->binding_handle, + frame, + &scmanager_handle, + service_name, + NULL, + SERVICE_ALL_ACCESS, + SERVICE_TYPE_WIN32_OWN_PROCESS | + ((flags & SVC_INTERACTIVE) ? + SERVICE_TYPE_INTERACTIVE_PROCESS : 0), + SVCCTL_DEMAND_START, + SVCCTL_SVC_ERROR_NORMAL, + service_filename, + NULL, + NULL, + NULL, + 0, + NULL, + NULL, + 0, + &service_handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_CreateServiceW " + "failed: %s\n", nt_errstr(status)); + goto close_scmanager; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_CreateServiceW " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_scmanager; + } + } + + status = dcerpc_svcctl_QueryServiceStatus( + rpccli->binding_handle, + frame, + &service_handle, + &service_status, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_QueryServiceStatus " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_QueryServiceStatus " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + + if (!(flags & SVC_IGNORE_INTERACTIVE)) { + need_conf = + !(service_status.type & + SERVICE_TYPE_INTERACTIVE_PROCESS) ^ + !(flags & SVC_INTERACTIVE); + } + + if (service_status.state == SVCCTL_STOPPED) { + need_start = true; + } else if (need_conf) { + status = dcerpc_svcctl_ControlService( + rpccli->binding_handle, + frame, + &service_handle, + SVCCTL_CONTROL_STOP, + &service_status, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_ControlServiceStatus " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_ControlServiceStatus " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + + do { + smb_msleep(100); + + status = dcerpc_svcctl_QueryServiceStatus( + rpccli->binding_handle, + frame, + &service_handle, + &service_status, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_QueryServiceStatus " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_QueryServiceStatus " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + } while (service_status.state == SVCCTL_STOP_PENDING); + + need_start = 1; + } + + if (need_conf) { + status = dcerpc_svcctl_ChangeServiceConfigW( + rpccli->binding_handle, + frame, + &service_handle, + SERVICE_TYPE_WIN32_OWN_PROCESS | + ((flags & SVC_INTERACTIVE) ? + SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */ + UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */ + UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */ + NULL, /* binary_path */ + NULL, /* load_order_group */ + NULL, /* tag_id */ + NULL, /* dependencies */ + 0, /* dwDependSize */ + NULL, /* service_start_name */ + NULL, /* password */ + 0, /* dwPwSize */ + NULL, /* display_name */ + &werr); + + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + } + + if (need_start) { + status = winexe_svc_upload( + hostname, + port, + service_filename, + svc32_exe, + svc64_exe, + credentials, + flags); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("winexe_svc_upload failed: %s\n", + nt_errstr(status)); + goto close_service; + } + + status = dcerpc_svcctl_StartServiceW( + rpccli->binding_handle, + frame, + &service_handle, + 0, /* num_args */ + NULL, /* arguments */ + &werr); + + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_StartServiceW " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_StartServiceW " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + + do { + smb_msleep(100); + + status = dcerpc_svcctl_QueryServiceStatus( + rpccli->binding_handle, + frame, + &service_handle, + &service_status, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_QueryServiceStatus " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_QueryServiceStatus " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + } while (service_status.state == SVCCTL_START_PENDING); + + if (service_status.state != SVCCTL_RUNNING) { + DBG_WARNING("Failed to start service\n"); + status = NT_STATUS_UNSUCCESSFUL; + goto close_service; + } + } + +close_service: + { + NTSTATUS close_status; + WERROR close_werr; + + close_status = dcerpc_svcctl_CloseServiceHandle( + rpccli->binding_handle, + frame, + &service_handle, + &close_werr); + if (!NT_STATUS_IS_OK(close_status)) { + DBG_WARNING("dcerpc_svcctl_CloseServiceHandle " + "failed: %s\n", nt_errstr(close_status)); + goto done; + } + if (!W_ERROR_IS_OK(close_werr)) { + DBG_WARNING("dcerpc_svcctl_CloseServiceHandle " + " failed: %s\n", win_errstr(close_werr)); + goto done; + } + } + +close_scmanager: + { + NTSTATUS close_status; + WERROR close_werr; + + close_status = dcerpc_svcctl_CloseServiceHandle( + rpccli->binding_handle, + frame, + &scmanager_handle, + &close_werr); + if (!NT_STATUS_IS_OK(close_status)) { + DBG_WARNING("dcerpc_svcctl_CloseServiceHandle " + "failed: %s\n", nt_errstr(close_status)); + goto done; + } + if (!W_ERROR_IS_OK(close_werr)) { + DBG_WARNING("dcerpc_svcctl_CloseServiceHandle " + " failed: %s\n", win_errstr(close_werr)); + goto done; + } + } + +done: + TALLOC_FREE(rpccli); + TALLOC_FREE(frame); + return status; +} + +static NTSTATUS winexe_svc_uninstall( + struct cli_state *cli, + const char *service_name) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct rpc_pipe_client *rpccli; + struct policy_handle scmanager_handle; + struct policy_handle service_handle; + struct SERVICE_STATUS service_status; + NTSTATUS status; + WERROR werr; + const char *remote_name = smbXcli_conn_remote_name(cli->conn); + const struct sockaddr_storage *remote_sockaddr = + smbXcli_conn_remote_sockaddr(cli->conn); + + status = cli_rpc_pipe_open_noauth_transport( + cli, + NCACN_NP, + &ndr_table_svcctl, + remote_name, + remote_sockaddr, + &rpccli); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n", + nt_errstr(status)); + goto done; + } + + status = dcerpc_svcctl_OpenSCManagerW( + rpccli->binding_handle, + frame, + remote_name, + NULL, + SEC_FLAG_MAXIMUM_ALLOWED, + &scmanager_handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n", + nt_errstr(status)); + goto done; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n", + win_errstr(werr)); + goto done; + } + + status = dcerpc_svcctl_OpenServiceW( + rpccli->binding_handle, + frame, + &scmanager_handle, + service_name, + SERVICE_ALL_ACCESS, + &service_handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n", + nt_errstr(status)); + goto close_scmanager; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n", + win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_scmanager; + } + + status = dcerpc_svcctl_ControlService( + rpccli->binding_handle, + frame, + &service_handle, + SVCCTL_CONTROL_STOP, + &service_status, + &werr); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_ControlServiceStatus " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_ControlServiceStatus " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + + do { + smb_msleep(100); + + status = dcerpc_svcctl_QueryServiceStatus( + rpccli->binding_handle, + frame, + &service_handle, + &service_status, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_QueryServiceStatus " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_QueryServiceStatus " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + } while (service_status.state != SVCCTL_STOPPED); + + status = dcerpc_svcctl_DeleteService( + rpccli->binding_handle, + frame, + &service_handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dcerpc_svcctl_DeleteService " + "failed: %s\n", nt_errstr(status)); + goto close_service; + } + if (!W_ERROR_IS_OK(werr)) { + DBG_WARNING("dcerpc_svcctl_DeleteService " + "failed: %s\n", win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto close_service; + } + +close_service: + { + NTSTATUS close_status; + WERROR close_werr; + + close_status = dcerpc_svcctl_CloseServiceHandle( + rpccli->binding_handle, + frame, + &service_handle, + &close_werr); + if (!NT_STATUS_IS_OK(close_status)) { + DBG_WARNING("dcerpc_svcctl_CloseServiceHandle " + "failed: %s\n", nt_errstr(close_status)); + goto done; + } + if (!W_ERROR_IS_OK(close_werr)) { + DBG_WARNING("dcerpc_svcctl_CloseServiceHandle " + " failed: %s\n", win_errstr(close_werr)); + goto done; + } + } + +close_scmanager: + { + NTSTATUS close_status; + WERROR close_werr; + + close_status = dcerpc_svcctl_CloseServiceHandle( + rpccli->binding_handle, + frame, + &scmanager_handle, + &close_werr); + if (!NT_STATUS_IS_OK(close_status)) { + DBG_WARNING("dcerpc_svcctl_CloseServiceHandle " + "failed: %s\n", nt_errstr(close_status)); + goto done; + } + if (!W_ERROR_IS_OK(close_werr)) { + DBG_WARNING("dcerpc_svcctl_CloseServiceHandle " + " failed: %s\n", win_errstr(close_werr)); + goto done; + } + } + +done: + TALLOC_FREE(rpccli); + TALLOC_FREE(frame); + return status; +} + +struct winexe_out_pipe_state { + struct tevent_context *ev; + struct cli_state *cli; + uint16_t out_pipe; + int out_fd; + char out_inbuf[256]; +}; + +static void winexe_out_pipe_opened(struct tevent_req *subreq); +static void winexe_out_pipe_got_data(struct tevent_req *subreq); +static void winexe_out_pipe_closed(struct tevent_req *subreq); + +static struct tevent_req *winexe_out_pipe_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *pipe_name, + int out_fd) +{ + struct tevent_req *req, *subreq; + struct winexe_out_pipe_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winexe_out_pipe_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + state->out_fd = out_fd; + + subreq = cli_ntcreate_send( + state, + state->ev, + state->cli, + pipe_name, + 0, + SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE| + SEC_RIGHTS_FILE_EXECUTE, + 0, /* FileAttributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, /* CreateDisposition */ + 0, /* CreateOptions */ + SMB2_IMPERSONATION_IMPERSONATION, + 0); /* SecurityFlags */ + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winexe_out_pipe_opened, req); + return req; +} + +static void winexe_out_pipe_opened(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_out_pipe_state *state = tevent_req_data( + req, struct winexe_out_pipe_state); + int timeout; + NTSTATUS status; + + status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + timeout = state->cli->timeout; + state->cli->timeout = 0; + + subreq = cli_read_send( + state, + state->ev, + state->cli, + state->out_pipe, + state->out_inbuf, + 0, + sizeof(state->out_inbuf)); + + state->cli->timeout = timeout; + + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req); +} + +static void winexe_out_pipe_got_data(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_out_pipe_state *state = tevent_req_data( + req, struct winexe_out_pipe_state); + NTSTATUS status; + int timeout; + size_t received; + ssize_t written; + + status = cli_read_recv(subreq, &received); + TALLOC_FREE(subreq); + + DBG_DEBUG("cli_read for %d gave %s\n", + state->out_fd, + nt_errstr(status)); + + if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) { + subreq = cli_close_send(state, + state->ev, + state->cli, + state->out_pipe, + 0); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_out_pipe_closed, req); + return; + } + + if (tevent_req_nterror(req, status)) { + return; + } + + if (received > 0) { + written = sys_write(state->out_fd, state->out_inbuf, received); + if (written == -1) { + tevent_req_nterror(req, map_nt_error_from_unix(errno)); + return; + } + } + + timeout = state->cli->timeout; + state->cli->timeout = 0; + + subreq = cli_read_send( + state, + state->ev, + state->cli, + state->out_pipe, + state->out_inbuf, + 0, + sizeof(state->out_inbuf)); + + state->cli->timeout = timeout; + + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req); +} + +static void winexe_out_pipe_closed(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_close_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + tevent_req_done(req); +} + +static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +struct winexe_in_pipe_state { + struct tevent_context *ev; + struct cli_state *cli; + struct tevent_req *fd_read_req; + bool close_requested; + bool closing; + uint16_t in_pipe; + int in_fd; + char inbuf[256]; +}; + +static void winexe_in_pipe_opened(struct tevent_req *subreq); +static void winexe_in_pipe_got_data(struct tevent_req *subreq); +static void winexe_in_pipe_written(struct tevent_req *subreq); +static void winexe_in_pipe_closed(struct tevent_req *subreq); + +static struct tevent_req *winexe_in_pipe_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *pipe_name, + int in_fd) +{ + struct tevent_req *req, *subreq; + struct winexe_in_pipe_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winexe_in_pipe_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + state->in_fd = in_fd; + + subreq = cli_ntcreate_send( + state, + state->ev, + state->cli, + pipe_name, + 0, + SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE| + SEC_RIGHTS_FILE_EXECUTE, + 0, /* FileAttributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, /* CreateDisposition */ + 0, /* CreateOptions */ + SMB2_IMPERSONATION_IMPERSONATION, + 0); /* SecurityFlags */ + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winexe_in_pipe_opened, req); + return req; +} + +static void winexe_in_pipe_opened(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_in_pipe_state *state = tevent_req_data( + req, struct winexe_in_pipe_state); + NTSTATUS status; + + status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + subreq = wait_for_read_send( + state, + state->ev, + state->in_fd, + true); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req); + + state->fd_read_req = subreq; +} + +static void winexe_in_pipe_got_data(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_in_pipe_state *state = tevent_req_data( + req, struct winexe_in_pipe_state); + int err; + bool ok; + int timeout; + ssize_t nread; + + ok = wait_for_read_recv(subreq, &err); + TALLOC_FREE(subreq); + if (!ok) { + tevent_req_nterror(req, map_nt_error_from_unix(err)); + return; + } + state->fd_read_req = NULL; + + nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf)); + if (nread == -1) { + tevent_req_nterror(req, map_nt_error_from_unix(errno)); + return; + } + if (nread == 0) { + tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED); + return; + } + + timeout = state->cli->timeout; + state->cli->timeout = 0; + + subreq = cli_writeall_send( + state, + state->ev, + state->cli, + state->in_pipe, + 0, + (uint8_t *)state->inbuf, + 0, + nread); + + state->cli->timeout = timeout; + + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_in_pipe_written, req); +} + +static void winexe_in_pipe_written(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_in_pipe_state *state = tevent_req_data( + req, struct winexe_in_pipe_state); + NTSTATUS status; + + status = cli_writeall_recv(subreq, NULL); + TALLOC_FREE(subreq); + + DBG_DEBUG("cli_writeall for %d gave %s\n", + state->in_fd, + nt_errstr(status)); + + if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) || + state->close_requested) { + subreq = cli_close_send(state, + state->ev, + state->cli, + state->in_pipe, + 0); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_in_pipe_closed, req); + state->closing = true; + return; + } + + if (tevent_req_nterror(req, status)) { + return; + } + + subreq = wait_for_read_send( + state, + state->ev, + state->in_fd, + true); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req); + + state->fd_read_req = subreq; +} + +static void winexe_in_pipe_closed(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_close_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + return tevent_req_done(req); +} + +static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +static bool winexe_in_pipe_close(struct tevent_req *req) +{ + struct winexe_in_pipe_state *state = tevent_req_data( + req, struct winexe_in_pipe_state); + struct tevent_req *subreq; + + if (state->closing) { + return true; + } + + if (state->fd_read_req == NULL) { + /* + * cli_writeall active, wait for it to return + */ + state->close_requested = true; + return true; + } + + TALLOC_FREE(state->fd_read_req); + + subreq = + cli_close_send(state, state->ev, state->cli, state->in_pipe, 0); + if (subreq == NULL) { + return false; + } + tevent_req_set_callback(subreq, winexe_in_pipe_closed, req); + state->closing = true; + + return true; +} + +struct winexe_pipes_state { + struct tevent_req *pipes[3]; +}; + +static void winexe_pipes_stdin_done(struct tevent_req *subreq); +static void winexe_pipes_stdout_done(struct tevent_req *subreq); +static void winexe_pipes_stderr_done(struct tevent_req *subreq); + +static struct tevent_req *winexe_pipes_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *pipe_postfix) +{ + struct tevent_req *req; + struct winexe_pipes_state *state; + char *pipe_name; + + req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state); + if (req == NULL) { + return NULL; + } + + pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix); + if (tevent_req_nomem(pipe_name, req)) { + return tevent_req_post(req, ev); + } + state->pipes[0] = winexe_in_pipe_send( + state, + ev, + cli, + pipe_name, + 0); + if (tevent_req_nomem(state->pipes[0], req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req); + + pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix); + if (tevent_req_nomem(pipe_name, req)) { + return tevent_req_post(req, ev); + } + state->pipes[1] = winexe_out_pipe_send( + state, + ev, + cli, + pipe_name, + 1); + if (tevent_req_nomem(state->pipes[1], req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done, + req); + + pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix); + if (tevent_req_nomem(pipe_name, req)) { + return tevent_req_post(req, ev); + } + state->pipes[2] = winexe_out_pipe_send( + state, + ev, + cli, + pipe_name, + 2); + if (tevent_req_nomem(state->pipes[2], req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done, + req); + + DBG_DEBUG("pipes = %p %p %p\n", + state->pipes[0], + state->pipes[1], + state->pipes[2]); + + return req; +} + +static void winexe_pipes_stdin_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_pipes_state *state = tevent_req_data( + req, struct winexe_pipes_state); + NTSTATUS status; + + status = winexe_in_pipe_recv(subreq); + TALLOC_FREE(subreq); + + DBG_DEBUG("stdin returned %s\n", nt_errstr(status)); + + if (tevent_req_nterror(req, status)) { + return; + } + + state->pipes[0] = NULL; + + DBG_DEBUG("pipes = %p %p %p\n", + state->pipes[0], + state->pipes[1], + state->pipes[2]); + + if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) { + tevent_req_done(req); + } +} + +static void winexe_pipes_stdout_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_pipes_state *state = tevent_req_data( + req, struct winexe_pipes_state); + NTSTATUS status; + + status = winexe_out_pipe_recv(subreq); + TALLOC_FREE(subreq); + + DBG_DEBUG("stdout returned %s\n", nt_errstr(status)); + + if (tevent_req_nterror(req, status)) { + return; + } + + if (state->pipes[0] != NULL) { + winexe_in_pipe_close(state->pipes[0]); + } + + state->pipes[1] = NULL; + + DBG_DEBUG("pipes = %p %p %p\n", + state->pipes[0], + state->pipes[1], + state->pipes[2]); + + if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) { + tevent_req_done(req); + } +} + +static void winexe_pipes_stderr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_pipes_state *state = tevent_req_data( + req, struct winexe_pipes_state); + NTSTATUS status; + + status = winexe_out_pipe_recv(subreq); + TALLOC_FREE(subreq); + + DBG_DEBUG("stderr returned %s\n", nt_errstr(status)); + + if (tevent_req_nterror(req, status)) { + return; + } + + if (state->pipes[0] != NULL) { + winexe_in_pipe_close(state->pipes[0]); + } + + state->pipes[2] = NULL; + + DBG_DEBUG("pipes = %p %p %p\n", + state->pipes[0], + state->pipes[1], + state->pipes[2]); + + if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) { + tevent_req_done(req); + } +} + +static NTSTATUS winexe_pipes_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +struct winexe_ctrl_state { + struct tevent_context *ev; + struct cli_state *cli; + + uint16_t ctrl_pipe; + bool ctrl_pipe_done; + + char ctrl_inbuf[256]; + char *cmd; + int return_code; + + struct tevent_req *pipes_req; +}; + +static void winexe_ctrl_opened(struct tevent_req *subreq); +static void winexe_ctrl_got_read(struct tevent_req *subreq); +static void winexe_ctrl_wrote_version(struct tevent_req *subreq); +static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq); +static void winexe_ctrl_pipes_done(struct tevent_req *subreq); +static void winexe_ctrl_pipe_closed(struct tevent_req *subreq); + +static struct tevent_req *winexe_ctrl_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *cmd) +{ + struct tevent_req *req, *subreq; + struct winexe_ctrl_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winexe_ctrl_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + + state->cmd = talloc_asprintf(state, "run %s\n", cmd); + if (tevent_req_nomem(state->cmd, req)) { + return tevent_req_post(req, ev); + } + + subreq = cli_ntcreate_send( + state, + state->ev, + state->cli, + "\\" PIPE_NAME, + 0, + SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE| + SEC_RIGHTS_FILE_EXECUTE, + 0, /* FileAttributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, /* CreateDisposition */ + 0, /* CreateOptions */ + SMB2_IMPERSONATION_IMPERSONATION, + 0); /* SecurityFlags */ + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winexe_ctrl_opened, req); + return req; +} + +static void winexe_ctrl_opened(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_ctrl_state *state = tevent_req_data( + req, struct winexe_ctrl_state); + int timeout; + NTSTATUS status; + static const char cmd[] = "get codepage\nget version\n"; + + status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + timeout = state->cli->timeout; + state->cli->timeout = 0; + + subreq = cli_read_send( + state, + state->ev, + state->cli, + state->ctrl_pipe, + state->ctrl_inbuf, + 0, + sizeof(state->ctrl_inbuf)-1); + + state->cli->timeout = timeout; + + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_ctrl_got_read, req); + + subreq = cli_writeall_send( + state, + state->ev, + state->cli, + state->ctrl_pipe, + 0, + (const uint8_t *)cmd, + 0, + strlen(cmd)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req); +} + +static void winexe_ctrl_got_read(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_ctrl_state *state = tevent_req_data( + req, struct winexe_ctrl_state); + NTSTATUS status; + int timeout; + size_t received; + unsigned int version, return_code; + int ret; + + status = cli_read_recv(subreq, &received); + TALLOC_FREE(subreq); + + if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) { + subreq = cli_close_send(state, + state->ev, + state->cli, + state->ctrl_pipe, + 0); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req); + return; + } + if (tevent_req_nterror(req, status)) { + return; + } + + DBG_DEBUG("Got %zu bytes\n", received); + + timeout = state->cli->timeout; + state->cli->timeout = 0; + + subreq = cli_read_send( + state, + state->ev, + state->cli, + state->ctrl_pipe, + state->ctrl_inbuf, + 0, + sizeof(state->ctrl_inbuf)-1); + + state->cli->timeout = timeout; + + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_ctrl_got_read, req); + + ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version); + if (ret == 1) { + DBG_DEBUG("Got version %x\n", version); + + subreq = cli_writeall_send( + state, + state->ev, + state->cli, + state->ctrl_pipe, + 0, + (const uint8_t *)state->cmd, + 0, + strlen(state->cmd)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req); + return; + } + + ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err ")); + if (ret == 0) { + char *p = state->ctrl_inbuf + 11; + char *q = strchr(state->ctrl_inbuf, '\n'); + char *postfix; + size_t postfix_len; + + if (q == NULL) { + DBG_DEBUG("Got invalid pipe postfix\n"); + return; + } + + postfix_len = q - p; + + postfix = talloc_strndup(state, p, postfix_len); + if (tevent_req_nomem(postfix, req)) { + return; + } + + DBG_DEBUG("Got pipe postfix %s\n", postfix); + + subreq = winexe_pipes_send( + state, + state->ev, + state->cli, + postfix); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req); + + state->pipes_req = subreq; + + return; + } + + ret = strncmp(state->ctrl_inbuf, "error ", strlen("error ")); + if (ret == 0) { + printf("Error: %s", state->ctrl_inbuf); + return; + } + + ret = sscanf(state->ctrl_inbuf, "return_code %x\n", &return_code); + if (ret == 1) { + state->return_code = return_code; + return; + } +} + +static void winexe_ctrl_wrote_version(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_writeall_recv(subreq, NULL); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } +} + +static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_writeall_recv(subreq, NULL); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } +} + +static void winexe_ctrl_pipe_closed(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_ctrl_state *state = tevent_req_data( + req, struct winexe_ctrl_state); + NTSTATUS status; + + status = cli_close_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + state->ctrl_pipe_done = true; + if (state->pipes_req == NULL) { + tevent_req_done(req); + } +} + +static void winexe_ctrl_pipes_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winexe_ctrl_state *state = tevent_req_data( + req, struct winexe_ctrl_state); + NTSTATUS status; + + status = winexe_pipes_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + state->pipes_req = NULL; + if (state->ctrl_pipe_done) { + tevent_req_done(req); + } +} + +static NTSTATUS winexe_ctrl_recv(struct tevent_req *req, + int *preturn_code) +{ + struct winexe_ctrl_state *state = tevent_req_data( + req, struct winexe_ctrl_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (preturn_code != NULL) { + *preturn_code = state->return_code; + } + return NT_STATUS_OK; +} + +static NTSTATUS winexe_ctrl(struct cli_state *cli, + const char *cmd, + int *preturn_code) +{ + struct tevent_context *ev = NULL; + struct tevent_req *req = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + bool ok; + + ev = samba_tevent_context_init(cli); + if (ev == NULL) { + goto done; + } + req = winexe_ctrl_send(ev, ev, cli, cmd); + if (req == NULL) { + goto done; + } + ok = tevent_req_poll_ntstatus(req, ev, &status); + if (!ok) { + goto done; + } + status = winexe_ctrl_recv(req, preturn_code); +done: + TALLOC_FREE(req); + TALLOC_FREE(ev); + return status; +} + +#ifdef HAVE_WINEXE_CC_WIN32 +const DATA_BLOB *winexesvc32_exe_binary(void); +#endif + +#ifdef HAVE_WINEXE_CC_WIN64 +const DATA_BLOB *winexesvc64_exe_binary(void); +#endif + +int main(int argc, char *argv[]) +{ + TALLOC_CTX *frame = talloc_stackframe(); + const char **const_argv = discard_const_p(const char *, argv); + struct program_options options = {0}; + struct cli_state *cli = NULL; + const char *service_name = SERVICE_NAME; + char *service_filename = NULL; +#ifdef HAVE_WINEXE_CC_WIN32 + const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary(); +#else + const DATA_BLOB *winexesvc32_exe = NULL; +#endif +#ifdef HAVE_WINEXE_CC_WIN64 + const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary(); +#else + const DATA_BLOB *winexesvc64_exe = NULL; +#endif + NTSTATUS status; + int ret = 1; + int return_code = 0; + + smb_init_locale(); + + parse_args(argc, const_argv, frame, &options); + + samba_cmdline_burn(argc, argv); + + if (options.cmd == NULL) { + fprintf(stderr, "no cmd given\n"); + goto done; + } + + service_filename = talloc_asprintf(frame, "%s.exe", service_name); + if (service_filename == NULL) { + DBG_WARNING("talloc_asprintf failed\n"); + goto done; + } + + status = cli_full_connection_creds( + &cli, + lp_netbios_name(), + options.hostname, + NULL, + options.port, + "IPC$", + "IPC", + options.credentials, + CLI_FULL_CONNECTION_IPC); + + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("cli_full_connection_creds failed: %s\n", + nt_errstr(status)); + goto done; + } + + status = winexe_svc_install( + cli, + options.hostname, + options.port, + service_name, + service_filename, + winexesvc32_exe, + winexesvc64_exe, + options.credentials, + options.flags); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("winexe_svc_install failed: %s\n", + nt_errstr(status)); + goto done; + } + + status = winexe_ctrl(cli, options.cmd, &return_code); + if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) { + /* Normal finish */ + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("cli_ctrl failed: %s\n", + nt_errstr(status)); + goto done; + } + + if (options.flags & SVC_UNINSTALL) { + status = winexe_svc_uninstall( + cli, + service_name); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("winexe_svc_uninstall failed: %s\n", + nt_errstr(status)); + goto done; + } + } + + ret = return_code; +done: + TALLOC_FREE(frame); + return ret; +} diff --git a/examples/winexe/winexesvc.c b/examples/winexe/winexesvc.c new file mode 100644 index 0000000..3d2ebcc --- /dev/null +++ b/examples/winexe/winexesvc.c @@ -0,0 +1,745 @@ +/* + * Copyright (C) Andrzej Hajda 2009-2013 + * Contact: andrzej.hajda@wp.pl + * + * Source of this file: https://git.code.sf.net/p/winexe/winexe-waf + * commit b787d2a2c4b1abc3653bad10aec943b8efcd7aab. + * + * ** NOTE! The following "GPLv3 only" license applies to the winexe + * ** service files. This does NOT imply that all of Samba is released + * ** under the "GPLv3 only" license. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 3 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <windows.h> +#include <aclapi.h> +#include <userenv.h> + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> + +#include "winexesvc.h" + +#define BUFSIZE 256 + +#if 0 +#define dbg(arg...) \ +({\ + FILE *f = fopen("C:\\" SERVICE_NAME ".log", "at");\ + if (f) {\ + fprintf(f, arg);\ + fclose(f);\ + }\ +}) +#else +#define dbg(arg...) +#endif + +static SECURITY_ATTRIBUTES sa; + +/* Creates SECURITY_ATTRIBUTES sa with full access for BUILTIN\Administrators */ +static int CreatePipesSA() +{ + DWORD dwRes; + PSID pAdminSID = NULL; + PACL pACL = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + EXPLICIT_ACCESS ea; + SID_IDENTIFIER_AUTHORITY SIDAuthNT = {SECURITY_NT_AUTHORITY}; + + /* Create a SID for the BUILTIN\Administrators group. */ + if ( + !AllocateAndInitializeSid( + &SIDAuthNT, 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, &pAdminSID + ) + ) { + dbg("AllocateAndInitializeSid Error %lu\n", GetLastError()); + return 0; + } + /* Initialize an EXPLICIT_ACCESS structure for an ACE. + The ACE will allow the Administrators group full access to the key. + */ + ea.grfAccessPermissions = FILE_ALL_ACCESS; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP; + ea.Trustee.ptstrName = (LPTSTR) pAdminSID; + + /* Create a new ACL that contains the new ACEs */ + dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL); + if (ERROR_SUCCESS != dwRes) { + dbg("SetEntriesInAcl Error %lu\n", GetLastError()); + return 0; + } + /* Initialize a security descriptor */ + pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + if (NULL == pSD) { + dbg("LocalAlloc Error %lu\n", GetLastError()); + return 0; + } + + if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) + { + dbg("InitializeSecurityDescriptor Error %lu\n", GetLastError()); + return 0; + } + /* Add the ACL to the security descriptor */ + if ( + !SetSecurityDescriptorDacl( + pSD, TRUE, /* bDaclPresent flag */ + pACL, FALSE /* not a default DACL */ + ) + ) { + dbg("SetSecurityDescriptorDacl Error %lu\n", GetLastError()); + return 0; + } + /* Initialize a security attributes structure */ + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + return 1; +} + +typedef struct { + HANDLE h; + OVERLAPPED o; +} OV_HANDLE; + +static int hgets(char *str, int n, OV_HANDLE *pipe) +{ + DWORD res; + DWORD count = 0; + --n; + while (--n >= 0) { + if (!ReadFile(pipe->h, str, 1, NULL, &pipe->o) && GetLastError() != ERROR_IO_PENDING) + goto finish; + if (!GetOverlappedResult(pipe->h, &pipe->o, &res, TRUE) || !res) + goto finish; + if (*str == '\n') + goto finish; + ++count; + ++str; + } +finish: + *str = 0; + return count; +} + +static int hprintf(OV_HANDLE *pipe, const char *fmt, ...) +{ + int res; + char buf[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + if (!WriteFile(pipe->h, buf, strlen(buf), NULL, &pipe->o) && GetLastError() == ERROR_IO_PENDING) + GetOverlappedResult(pipe->h, &pipe->o, (LPDWORD)&res, TRUE); + FlushFileBuffers(pipe->h); + return res; +} + +typedef struct { + OV_HANDLE *pipe; + const char *cmd; + HANDLE pin; + HANDLE pout; + HANDLE perr; + HANDLE token; + int implevel; + int system; + int profile; + char *runas; + int conn_number; +} connection_context; + +typedef int CMD_FUNC(connection_context *); + +typedef struct { + const char *name; + CMD_FUNC *func; +} CMD_ITEM; + +static int cmd_set(connection_context *c) +{ + static const char* var_system = "system"; + static const char* var_implevel = "implevel"; + static const char* var_runas = "runas"; + static const char* var_profile = "profile"; + char *cmdline; + int res = 0; + + cmdline = strchr(c->cmd, ' '); + if (!cmdline) { + goto finish; + } + ++cmdline; + int l; + if ((strstr(cmdline, var_system) == cmdline) && (cmdline[l = strlen(var_system)] == ' ')) { + c->system = atoi(cmdline + l + 1); + } else if ((strstr(cmdline, var_implevel) == cmdline) && (cmdline[l = strlen(var_implevel)] == ' ')) { + c->implevel = atoi(cmdline + l + 1); + } else if ((strstr(cmdline, var_profile) == cmdline) && (cmdline[l = strlen(var_profile)] == ' ')) { + c->profile = atoi(cmdline + l + 1); + } else if ((strstr(cmdline, var_runas) == cmdline) && (cmdline[l = strlen(var_runas)] == ' ')) { + c->runas = strdup(cmdline + l + 1); + } else { + hprintf(c->pipe, "error Unknown command (%s)\n", c->cmd); + goto finish; + } + res = 1; +finish: + return res; +} + +static int cmd_get(connection_context *c) +{ + static const char* var_version = "version"; + static const char* var_codepage = "codepage"; + char *cmdline; + int res = 0; + + cmdline = strchr(c->cmd, ' '); + if (!cmdline) { + goto finish; + } + ++cmdline; + int l; + if ((strstr(cmdline, var_version) == cmdline) + && (cmdline[l = strlen(var_version)] == 0)) { + hprintf(c->pipe, "version 0x%04X\n", VERSION); + } else if ((strstr(cmdline, var_codepage) == cmdline) + && (cmdline[l = strlen(var_codepage)] == 0)) { + hprintf(c->pipe, "codepage %d\n", GetOEMCP()); + } else { + hprintf(c->pipe, "error Unknown argument (%s)\n", c->cmd); + goto finish; + } + res = 1; +finish: + return res; +} + +typedef struct { + char *user; + char *domain; + char *password; +} credentials; + +static int prepare_credentials(char *str, credentials *crd) +{ + char *p; + p = strchr(str, '/'); + if (!p) p = strchr(str, '\\'); + if (p) { + *p++ = 0; + crd->domain = str; + } else { + p = str; + crd->domain = "."; + } + crd->user = p; + p = strchr(p, '%'); + if (p) + *p++ = 0; + crd->password = p; + return 1; +} + +static int get_token(connection_context *c) +{ + int res = 0; + int wres; + HANDLE token; + + if (c->runas) { + credentials crd; + if (!prepare_credentials(c->runas, &crd)) { + hprintf(c->pipe, "error Incorrect runas credentials\n"); + goto finish; + } + wres = LogonUser(crd.user, crd.domain, crd.password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &c->token); + if (!wres) { + hprintf(c->pipe, "error Cannot LogonUser(%s,%s,%s) %d\n", + crd.user, crd.domain, crd.password, GetLastError()); + goto finish; + } + res = 1; + goto finish; + } else if (c->system) { + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) { + hprintf(c->pipe, "error Cannot OpenProcessToken %d\n", GetLastError()); + goto finish; + } + } else { + if (!ImpersonateNamedPipeClient(c->pipe->h)) { + hprintf(c->pipe, "error Cannot ImpersonateNamedPipeClient %d\n", GetLastError()); + goto finish; + } + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) { + hprintf(c->pipe, "error Cannot OpenThreadToken %d\n", GetLastError()); + goto finishRevertToSelf; + } + } + if (!DuplicateTokenEx(token, MAXIMUM_ALLOWED, 0, c->implevel, TokenPrimary, &c->token)) { + hprintf(c->pipe, "error Cannot Duplicate Token %d\n", GetLastError()); + goto finishCloseToken; + } + res = 1; +finishCloseToken: + CloseHandle(token); +finishRevertToSelf: + if (!c->system) { + if (!RevertToSelf()) { + hprintf(c->pipe, "error Cannot RevertToSelf %d\n", GetLastError()); + res = 0; + } + } +finish: + return res; +} + +static int load_user_profile(connection_context *c) +{ + PROFILEINFO pi = { .dwSize = sizeof(PROFILEINFO) }; + DWORD ulen = 256; + TCHAR username[ulen]; + + GetUserName(username, &ulen); + pi.lpUserName = username; + + return LoadUserProfile(c->token, &pi); +} + +static int cmd_run(connection_context *c) +{ + char buf[256]; + int res = 0; + char *cmdline; + DWORD pipe_nr; + + cmdline = strchr(c->cmd, ' '); + if (!cmdline) { + goto finish; + } + ++cmdline; + + if (!get_token(c)) + return 0; + + pipe_nr = (GetCurrentProcessId() << 16) + (DWORD) c->conn_number; + + sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_IN, (unsigned int) pipe_nr); + c->pin = CreateNamedPipe(buf, + PIPE_ACCESS_DUPLEX, + PIPE_WAIT, + 1, + BUFSIZE, + BUFSIZE, + NMPWAIT_USE_DEFAULT_WAIT, + &sa); + if (c->pin == INVALID_HANDLE_VALUE) { + hprintf(c->pipe, "error Cannot create in pipe(%s), error 0x%08X\n", buf, GetLastError()); + goto finishCloseToken; + } + + sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_OUT, (unsigned int) pipe_nr); + c->pout = CreateNamedPipe(buf, + PIPE_ACCESS_DUPLEX, + PIPE_WAIT, + 1, + BUFSIZE, + BUFSIZE, + NMPWAIT_USE_DEFAULT_WAIT, + &sa); + if (c->pout == INVALID_HANDLE_VALUE) { + hprintf(c->pipe, "error Cannot create out pipe(%s), error 0x%08X\n", buf, GetLastError()); + goto finishClosePin; + } + + sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_ERR, (unsigned int) pipe_nr); + c->perr = CreateNamedPipe(buf, + PIPE_ACCESS_DUPLEX, + PIPE_WAIT, + 1, + BUFSIZE, + BUFSIZE, + NMPWAIT_USE_DEFAULT_WAIT, + &sa); + if (c->perr == INVALID_HANDLE_VALUE) { + hprintf(c->pipe, "error Cannot create err pipe(%s), error 0x%08x\n", buf, GetLastError()); + goto finishClosePout; + } + + /* Send handle to client (it will use it to connect pipes) */ + hprintf(c->pipe, CMD_STD_IO_ERR " %08X\n", pipe_nr); + + HANDLE ph[] = { c->pin, c->pout, c->perr }; + int i; + + for (i = 0; i < 3; ++i) { + if (ConnectNamedPipe(ph[i], NULL)) + continue; + int err = GetLastError(); + if (err != ERROR_PIPE_CONNECTED) { + hprintf(c->pipe, "error ConnectNamedPipe(pin) %d\n", err); + while (--i >= 0) + DisconnectNamedPipe(ph[i]); + goto finishClosePerr; + } + } + + SetHandleInformation(c->pin, HANDLE_FLAG_INHERIT, 1); + SetHandleInformation(c->pout, HANDLE_FLAG_INHERIT, 1); + SetHandleInformation(c->perr, HANDLE_FLAG_INHERIT, 1); + + if (c->profile) + load_user_profile(c); + + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + + STARTUPINFO si; + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.hStdInput = c->pin; + si.hStdOutput = c->pout; + si.hStdError = c->perr; + si.dwFlags |= STARTF_USESTDHANDLES; + + if (CreateProcessAsUser( + c->token, + NULL, + cmdline, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + TRUE, /* handles are inherited */ + 0, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &si, /* STARTUPINFO pointer */ + &pi) /* receives PROCESS_INFORMATION */ + ) { + HANDLE hlist[2] = {c->pipe->o.hEvent, pi.hProcess}; + DWORD ec; + char str[1]; + + if (!ResetEvent(c->pipe->o.hEvent)) + dbg("ResetEvent error - %lu\n", GetLastError()); + if (!ReadFile(c->pipe->h, str, 1, NULL, &c->pipe->o) && GetLastError() != ERROR_IO_PENDING) + dbg("ReadFile(control_pipe) error - %lu\n", GetLastError()); + ec = WaitForMultipleObjects(2, hlist, FALSE, INFINITE); + dbg("WaitForMultipleObjects=%lu\n", ec - WAIT_OBJECT_0); + if (ec != WAIT_OBJECT_0) + GetExitCodeProcess(pi.hProcess, &ec); + else + TerminateProcess(pi.hProcess, ec = 0x1234); + FlushFileBuffers(c->pout); + FlushFileBuffers(c->perr); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + hprintf(c->pipe, CMD_RETURN_CODE " %08X\n", ec); + } else { + hprintf(c->pipe, "error Creating process(%s) %d\n", cmdline, GetLastError()); + } + + DisconnectNamedPipe(c->perr); + DisconnectNamedPipe(c->pout); + DisconnectNamedPipe(c->pin); +finishClosePerr: + CloseHandle(c->perr); +finishClosePout: + CloseHandle(c->pout); +finishClosePin: + CloseHandle(c->pin); +finishCloseToken: + CloseHandle(c->token); +finish: + return res; +} + +static CMD_ITEM cmd_table[] = { + {"run", cmd_run}, + {"set", cmd_set}, + {"get", cmd_get}, + {NULL, NULL} +}; + +typedef struct { + OV_HANDLE *pipe; + int conn_number; +} connection_data; + +#define MAX_COMMAND_LENGTH (32768) + +static VOID handle_connection(connection_data *data) +{ + char *cmd = 0; + int res; + connection_context _c, *c = &_c; + cmd = malloc(MAX_COMMAND_LENGTH); + if (!cmd) { + hprintf(data->pipe, + "error: unable to allocate buffer for command\n"); + return; + } + ZeroMemory(cmd, MAX_COMMAND_LENGTH); + ZeroMemory(c, sizeof(connection_context)); + c->pipe = data->pipe; + c->cmd = cmd; + c->conn_number = data->conn_number; + free(data); + /* FIXME make wait for end of process or ctrl_pipe input */ + while (1) { + res = hgets(cmd, MAX_COMMAND_LENGTH, c->pipe); + if (res <= 0) { + dbg("Error reading from pipe(%p)\n", c->pipe->h); + goto finish; + } + dbg("Retrieved line: \"%s\"\n", cmd); + CMD_ITEM *ci; + for (ci = cmd_table; ci->name; ++ci) { + if (strstr(cmd, ci->name) != cmd) + continue; + char c = cmd[strlen(ci->name)]; + if (!c || (c == ' ')) + break; + } + if (ci->name) { + if (!ci->func(c)) + goto finish; + } else { + hprintf(c->pipe, "error Ignoring unknown command (%s)\n", cmd); + } + } +finish: + FlushFileBuffers(c->pipe->h); + DisconnectNamedPipe(c->pipe->h); + CloseHandle(c->pipe->h); + CloseHandle(c->pipe->o.hEvent); + free(c->pipe); + free(cmd); +} + +static int conn_number = 0; + +DWORD WINAPI winexesvc_loop(LPVOID lpParameter) +{ + BOOL res; + + dbg("server_loop: alive\n"); + if (!CreatePipesSA()) { + dbg("CreatePipesSA failed (%08lX)\n", GetLastError()); + return -1; + } + dbg("server_loop: CreatePipesSA done\n"); + for (;;) { + dbg("server_loop: Create Pipe\n"); + OV_HANDLE *pipe; + pipe = (OV_HANDLE *)malloc(sizeof(OV_HANDLE)); + ZeroMemory(&pipe->o, sizeof(OVERLAPPED)); + pipe->o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + pipe->h = CreateNamedPipe("\\\\.\\pipe\\" PIPE_NAME, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + BUFSIZE, + BUFSIZE, + NMPWAIT_USE_DEFAULT_WAIT, + &sa); + if (pipe->h == INVALID_HANDLE_VALUE) { + dbg("CreatePipe failed(%08lX)\n", + GetLastError()); + CloseHandle(pipe->o.hEvent); + free(pipe); + return 0; + } + + dbg("server_loop: Connect Pipe\n"); + if (ConnectNamedPipe(pipe->h, &pipe->o)) { + dbg("server_loop: Connect Pipe err %08lX\n", GetLastError()); + res = FALSE; + } else { + switch (GetLastError()) { + case ERROR_IO_PENDING: + dbg("server_loop: Connect Pipe(0) pending\n"); + DWORD t; + res = GetOverlappedResult(pipe->h, &pipe->o, &t, TRUE); + break; + case ERROR_PIPE_CONNECTED: + dbg("server_loop: Connect Pipe(0) connected\n"); + res = TRUE; + break; + default: + dbg("server_loop: Connect Pipe(0) err %08lX\n", GetLastError()); + res = FALSE; + } + } + + if (res) { + connection_data *cd = malloc(sizeof(connection_data)); + cd->pipe = pipe; + cd->conn_number = ++conn_number; + dbg("server_loop: CreateThread\n"); + HANDLE th = CreateThread(NULL, /* no security attribute */ + 0, /* default stack size */ + (LPTHREAD_START_ROUTINE) + handle_connection, + (LPVOID) cd, /* thread parameter */ + 0, /* not suspended */ + NULL); /* returns thread ID */ + if (!th) { + dbg("Cannot create thread\n"); + CloseHandle(pipe->h); + CloseHandle(pipe->o.hEvent); + free(pipe); + } else { + CloseHandle(th); + dbg("server_loop: Thread created\n"); + } + } else { + dbg("server_loop: Pipe not connected\n"); + CloseHandle(pipe->h); + CloseHandle(pipe->o.hEvent); + free(pipe); + } + } + dbg("server_loop: STH wrong\n"); + return 0; +} + +static SERVICE_STATUS winexesvcStatus; +static SERVICE_STATUS_HANDLE winexesvcStatusHandle; + +static VOID WINAPI winexesvcCtrlHandler(DWORD Opcode) +{ + switch (Opcode) { + case SERVICE_CONTROL_PAUSE: + dbg(SERVICE_NAME ": winexesvcCtrlHandler: pause\n", 0); + winexesvcStatus.dwCurrentState = SERVICE_PAUSED; + break; + + case SERVICE_CONTROL_CONTINUE: + dbg(SERVICE_NAME ": winexesvcCtrlHandler: continue\n", 0); + winexesvcStatus.dwCurrentState = SERVICE_RUNNING; + break; + + case SERVICE_CONTROL_STOP: + dbg(SERVICE_NAME ": winexesvcCtrlHandler: stop\n", 0); + winexesvcStatus.dwWin32ExitCode = 0; + winexesvcStatus.dwCurrentState = SERVICE_STOPPED; + winexesvcStatus.dwCheckPoint = 0; + winexesvcStatus.dwWaitHint = 0; + + if (!SetServiceStatus (winexesvcStatusHandle, &winexesvcStatus)) + dbg(SERVICE_NAME ": SetServiceStatus error %ld\n", GetLastError()); + + dbg(SERVICE_NAME ": Leaving winexesvc\n", 0); + return; + + case SERVICE_CONTROL_INTERROGATE: + dbg(SERVICE_NAME ": winexesvcCtrlHandler: interrogate\n", 0); + break; + + default: + dbg(SERVICE_NAME ": Unrecognized opcode %ld\n", Opcode); + } + + if (!SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus)) + dbg(SERVICE_NAME ": SetServiceStatus error 0x%08X\n", GetLastError()); + + return; +} + +static DWORD winexesvcInitialization(DWORD argc, LPTSTR * argv, DWORD * specificError) +{ + HANDLE th = CreateThread(NULL, 0, winexesvc_loop, NULL, 0, NULL); + if (th) { + CloseHandle(th); + return NO_ERROR; + } + return !NO_ERROR; +} + +static void WINAPI winexesvcStart(DWORD argc, LPTSTR * argv) +{ + DWORD status; + DWORD specificError; + + winexesvcStatus.dwServiceType = SERVICE_WIN32; + winexesvcStatus.dwCurrentState = SERVICE_START_PENDING; + winexesvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; + winexesvcStatus.dwWin32ExitCode = 0; + winexesvcStatus.dwServiceSpecificExitCode = 0; + winexesvcStatus.dwCheckPoint = 0; + winexesvcStatus.dwWaitHint = 0; + + dbg(SERVICE_NAME ": RegisterServiceCtrlHandler\n", 0); + + winexesvcStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, winexesvcCtrlHandler); + + if (winexesvcStatusHandle == (SERVICE_STATUS_HANDLE) 0) { + dbg(SERVICE_NAME + ": RegisterServiceCtrlHandler failed %d\n", + GetLastError()); + return; + } + status = winexesvcInitialization(argc, argv, &specificError); + + if (status != NO_ERROR) { + winexesvcStatus.dwCurrentState = SERVICE_STOPPED; + winexesvcStatus.dwCheckPoint = 0; + winexesvcStatus.dwWaitHint = 0; + winexesvcStatus.dwWin32ExitCode = status; + winexesvcStatus.dwServiceSpecificExitCode = specificError; + + SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus); + return; + } + + winexesvcStatus.dwCurrentState = SERVICE_RUNNING; + winexesvcStatus.dwCheckPoint = 0; + winexesvcStatus.dwWaitHint = 0; + + if (!SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus)) { + status = GetLastError(); + dbg(SERVICE_NAME ": SetServiceStatus error %ld\n", status); + } + + dbg(SERVICE_NAME ": Returning the Main Thread \n", 0); + + return; +} + +int main(int argc, char *argv[]) +{ + SERVICE_TABLE_ENTRY DispatchTable[] = { + {SERVICE_NAME, winexesvcStart}, + {NULL, NULL} + }; + + dbg(SERVICE_NAME ": StartServiceCtrlDispatcher %d\n", GetLastError()); + if (!StartServiceCtrlDispatcher(DispatchTable)) { + dbg(SERVICE_NAME + ": StartServiceCtrlDispatcher (%d)\n", + GetLastError()); + } + return 0; +} diff --git a/examples/winexe/winexesvc.h b/examples/winexe/winexesvc.h new file mode 100644 index 0000000..92b8375 --- /dev/null +++ b/examples/winexe/winexesvc.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) Andrzej Hajda 2009-2013 + * Contact: andrzej.hajda@wp.pl + * + * Source of this file: https://git.code.sf.net/p/winexe/winexe-waf + * commit b787d2a2c4b1abc3653bad10aec943b8efcd7aab. + * + * ** NOTE! The following "GPLv3 only" license applies to the winexe + * ** service files. This does NOT imply that all of Samba is released + * ** under the "GPLv3 only" license. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 3 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Shared by winexe and winexesvc + */ + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 1 + +#define VERSION ((VERSION_MAJOR * 100) + VERSION_MINOR) + +#define SERVICE_NAME "winexesvc" + +#define PIPE_NAME "ahexec" +#define PIPE_NAME_IN "ahexec_stdin%08X" +#define PIPE_NAME_OUT "ahexec_stdout%08X" +#define PIPE_NAME_ERR "ahexec_stderr%08X" + +#define CMD_STD_IO_ERR "std_io_err" +#define CMD_RETURN_CODE "return_code" diff --git a/examples/winexe/wscript b/examples/winexe/wscript new file mode 100644 index 0000000..6b311b1 --- /dev/null +++ b/examples/winexe/wscript @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +def configure(conf): + AR32 = ['i386', 'i586', 'i686'] + AR64 = ['x86_64', 'amd64'] + TC = ['mingw32', 'mingw32msvc', 'w64-mingw32'] + + found = False + + for a in AR32: + for t in TC: + if conf.find_program(a + '-' + t + '-gcc', var='WINEXE_CC_WIN32'): + found = True + break + if found: + conf.DEFINE('HAVE_WINEXE_CC_WIN32', 1); + break + + found = False + + for a in AR64: + for t in TC: + if conf.find_program(a + '-' + t + '-gcc', var='WINEXE_CC_WIN64'): + found = True + break + if found: + conf.DEFINE('HAVE_WINEXE_CC_WIN64', 1); + break + + conf.DEFINE("WINEXE_LDFLAGS", + "-s -Wall -Wl,-Bstatic -Wl,-Bdynamic -luserenv") diff --git a/examples/winexe/wscript_build b/examples/winexe/wscript_build new file mode 100644 index 0000000..3646834 --- /dev/null +++ b/examples/winexe/wscript_build @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +import samba_utils + +def generate_winexesvc_c_from_exe(t): + '''generate a C source file with the contents of the given binary''' + src = t.inputs[0].bldpath(t.env) + tgt = t.outputs[0].bldpath(t.env) + fn = t.env.SAMBA_GENERATOR_VARS['WINEXE_FN'] + + try: + with open(src, 'rb') as f: + src_blob = f.read() + f.close() + except: + print('Failed to read %s to convert to C array' % (src)) + return -1 + + def c_array(src): + N = 0 + result = '' + while src: + l = src[:8] + src = src[8:] + # Even files opened in binary mode are read as type "str" in + # Python 2, so we need to get the integer ordinal of each + # character in the string before we try to convert it to hex. + if isinstance(l, str): + h = ' '.join(["0x%02X," % ord(x) for x in l]) + # Files opened in binary mode are read as type "bytes" in + # Python 3, so we can convert each individual integer in the + # array of bytes to hex directly. + else: + h = ' '.join(["0x%02X," % x for x in l]) + result += "\t\t%s\n" % (h) + return result + + src_array = c_array(src_blob) + if len(src_array) <= 0: + print('Failed to convert %s to C array' % (src)) + return -1 + + contents = ''' +#include "replace.h" +#include "lib/util/data_blob.h" + +const DATA_BLOB *%s(void); +const DATA_BLOB *%s(void) +{ +\tstatic const uint8_t array[] = { +%s +\t}; +\tstatic const DATA_BLOB blob = { +\t\t.data = discard_const_p(uint8_t, array), +\t\t.length = ARRAY_SIZE(array), +\t}; +\treturn &blob; +} +''' % (fn, fn, src_array) + + if not samba_utils.save_file(tgt, contents): + print('Failed to write C source file %s' % (tgt)) + return -1 + return 0 + +winexesvc_binaries = '' + +bld.SAMBA_GENERATOR( + 'winexesvc32_exe', + source='winexesvc.c', + target='winexesvc32.exe', + rule='${WINEXE_CC_WIN32} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}', + enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN32) + +vars = {"WINEXE_FN": "winexesvc32_exe_binary"} +bld.SAMBA_GENERATOR( + 'winexesvc32_exe_binary', + source='winexesvc32.exe', + target='winexesvc32_exe_binary.c', + group='build_source', + vars=vars, + rule=generate_winexesvc_c_from_exe, + enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN32) + +if bld.env.WINEXE_CC_WIN32: + winexesvc_binaries += ' winexesvc32_exe_binary.c' + +bld.SAMBA_GENERATOR( + 'winexesvc64_exe', + source='winexesvc.c', + target='winexesvc64.exe', + rule='${WINEXE_CC_WIN64} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}', + enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN64) + +vars = {"WINEXE_FN": "winexesvc64_exe_binary"} +bld.SAMBA_GENERATOR( + 'winexesvc64_exe_binary', + source='winexesvc64.exe', + target='winexesvc64_exe_binary.c', + group='build_source', + vars=vars, + rule=generate_winexesvc_c_from_exe, + enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN64) + +if bld.env.WINEXE_CC_WIN64: + winexesvc_binaries += ' winexesvc64_exe_binary.c' + +if winexesvc_binaries != '': + bld.SAMBA3_BINARY('winexe', + source='winexe.c ' + winexesvc_binaries, + deps=''' + CMDLINE_S3 + samba-credentials + LOADPARM_CTX + libsmb + msrpc3 + ''', + enabled=bld.env.build_winexe) |