diff options
author | Andrew Tridgell <tridge@samba.org> | 2009-03-31 11:58:37 +1100 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2009-03-31 11:58:37 +1100 |
commit | 631e688c821b78d09d77f5940074800525c554aa (patch) | |
tree | 74473f1727ea0afa27d9c15e50e4638c4d8faf28 /source4 | |
parent | 13be4d7ff42bd2b8bf5702a499c482404e5cd164 (diff) | |
parent | 4b8e4ea7286f045effb6feb4c7bf8c5ef4ed2f9b (diff) | |
download | samba-631e688c821b78d09d77f5940074800525c554aa.tar.gz samba-631e688c821b78d09d77f5940074800525c554aa.tar.bz2 samba-631e688c821b78d09d77f5940074800525c554aa.zip |
Merge branch 'master' into wspp-schema
Diffstat (limited to 'source4')
35 files changed, 1099 insertions, 462 deletions
diff --git a/source4/auth/config.m4 b/source4/auth/config.m4 index fb9ee58c60..9735b17cac 100644 --- a/source4/auth/config.m4 +++ b/source4/auth/config.m4 @@ -28,6 +28,8 @@ if test x"$ac_cv_header_sasl_sasl_h" = x"yes" -a x"$ac_cv_lib_ext_sasl2_sasl_cli SASL_CPPFLAGS="$CPPFLAGS" SASL_LDFLAGS="$LDFLAGS" LIB_REMOVE_USR_LIB(SASL_LDFLAGS) + CFLAGS_REMOVE_USR_INCLUDE(SASL_CPPFLAGS) + CFLAGS_REMOVE_USR_INCLUDE(SASL_CFLAGS) else SMB_ENABLE(cyrus_sasl,NO) fi diff --git a/source4/auth/credentials/credentials_krb5.h b/source4/auth/credentials/credentials_krb5.h index 0d0e9f330f..5e56752eb4 100644 --- a/source4/auth/credentials/credentials_krb5.h +++ b/source4/auth/credentials/credentials_krb5.h @@ -24,6 +24,7 @@ #define __CREDENTIALS_KRB5_H__ #include <gssapi/gssapi.h> +#include <gssapi/gssapi_krb5.h> #include <krb5.h> struct gssapi_creds_container { diff --git a/source4/auth/kerberos/clikrb5.c b/source4/auth/kerberos/clikrb5.c index cf87d13cf2..68e7eb90cc 100644 --- a/source4/auth/kerberos/clikrb5.c +++ b/source4/auth/kerberos/clikrb5.c @@ -74,13 +74,9 @@ void kerberos_free_data_contents(krb5_context context, krb5_data *pdata) { -#if defined(HAVE_KRB5_FREE_DATA_CONTENTS) if (pdata->data) { - krb5_free_data_contents(context, pdata); + krb5_data_free(pdata); } -#else - SAFE_FREE(pdata->data); -#endif } krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry) diff --git a/source4/build/m4/public.m4 b/source4/build/m4/public.m4 index bd98a400be..2bf63f0ca6 100644 --- a/source4/build/m4/public.m4 +++ b/source4/build/m4/public.m4 @@ -102,10 +102,12 @@ AC_DEFUN([SMB_EXT_LIB_FROM_PKGCONFIG], ac_cv_$1_libs_only_other="`$PKG_CONFIG --libs-only-other '$2'` `$PKG_CONFIG --libs-only-L '$2'`" LIB_REMOVE_USR_LIB(ac_cv_$1_libs_only_other) + ac_cv_$1_includedir_only="`$PKG_CONFIG --cflags-only-I '$2'`" + CFLAGS_REMOVE_USR_INCLUDE(ac_cv_$1_includedir_only) SMB_EXT_LIB($1, [`$PKG_CONFIG --libs-only-l '$2'`], [`$PKG_CONFIG --cflags-only-other '$2'`], - [`$PKG_CONFIG --cflags-only-I '$2'`], + [$ac_cv_$1_includedir_only], [$ac_cv_$1_libs_only_other]) ac_cv_$1_found=yes diff --git a/source4/build/make/rules.mk b/source4/build/make/rules.mk index 55ecf8968b..e9f4786d34 100644 --- a/source4/build/make/rules.mk +++ b/source4/build/make/rules.mk @@ -185,7 +185,8 @@ showflags:: base_srcdirs = $(srcdir) ../librpc/ ../lib/ ../libcli etags: - etags `find $(base_srcdirs) -name "*.[ch]"` + etags $(ETAGS_OPTIONS) `find $(base_srcdirs) -name "*.[ch]"` ctags: - ctags `find $(base_srcdirs) -name "*.[ch]"` + ctags $(CTAGS_OPTIONS) `find $(base_srcdirs) -name "*.[ch]"` + diff --git a/source4/configure.ac b/source4/configure.ac index 065a3300ca..3c23f27d68 100644 --- a/source4/configure.ac +++ b/source4/configure.ac @@ -44,14 +44,14 @@ AC_CONFIG_FILES(librpc/dcerpc_atsvc.pc) m4_include(min_versions.m4) -SMB_INCLUDED_LIB_PKGCONFIG(LIBTALLOC, talloc >= $TALLOC_MIN_VERSION, [], +SMB_INCLUDED_LIB_PKGCONFIG(LIBTALLOC, talloc >= TALLOC_MIN_VERSION, [], [ m4_include(../lib/talloc/libtalloc.m4) SMB_INCLUDE_MK(../lib/talloc/config.mk) ] ) -SMB_INCLUDED_LIB_PKGCONFIG(LIBTDB, tdb >= $TDB_MIN_VERSION, +SMB_INCLUDED_LIB_PKGCONFIG(LIBTDB, tdb >= TDB_MIN_VERSION, [], [ m4_include(../lib/tdb/libtdb.m4) @@ -67,7 +67,7 @@ SMB_INCLUDED_LIB_PKGCONFIG(LIBTEVENT, tevent = TEVENT_REQUIRED_VERSION, SMB_INCLUDE_MK(../lib/tevent/python.mk) -SMB_INCLUDED_LIB_PKGCONFIG(LIBLDB, ldb = $LDB_REQUIRED_VERSION, +SMB_INCLUDED_LIB_PKGCONFIG(LIBLDB, ldb = LDB_REQUIRED_VERSION, [ SMB_INCLUDE_MK(lib/ldb/ldb_ildap/config.mk) SMB_INCLUDE_MK(lib/ldb/tools/config.mk) diff --git a/source4/dsdb/samdb/ldb_modules/tests/possibleinferiors.py b/source4/dsdb/samdb/ldb_modules/tests/possibleinferiors.py new file mode 100755 index 0000000000..aab93e59a3 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/tests/possibleinferiors.py @@ -0,0 +1,246 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Andrew Tridgell 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/>. +# + +"""Tests the possibleInferiors generation in the schema_fsmo ldb module""" + +import optparse +import sys + + +# Find right directory when running from source tree +sys.path.insert(0, "bin/python") + +import samba +from samba import getopt as options, Ldb +import ldb + +parser = optparse.OptionParser("possibleinferiors.py <URL> [<CLASS>]") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) +credopts = options.CredentialsOptions(parser) +parser.add_option_group(credopts) +parser.add_option_group(options.VersionOptions(parser)) +parser.add_option("--wspp", action="store_true") + +opts, args = parser.parse_args() + +if len(args) < 1: + parser.print_usage() + sys.exit(1) + +url = args[0] +if (len(args) > 1): + objectclass = args[1] +else: + objectclass = None + +def uniq_list(alist): + """return a unique list""" + set = {} + return [set.setdefault(e,e) for e in alist if e not in set] + + +lp_ctx = sambaopts.get_loadparm() + +creds = credopts.get_credentials(lp_ctx) +db = Ldb(url, credentials=creds, lp=lp_ctx, options=["modules:paged_searches"]) + +# get the rootDSE +res = db.search(base="", expression="", + scope=ldb.SCOPE_BASE, + attrs=["schemaNamingContext"]) +rootDse = res[0] + +schema_base = rootDse["schemaNamingContext"][0] + +def possible_inferiors_search(db, oc): + """return the possible inferiors via a search for the possibleInferiors attribute""" + res = db.search(base=schema_base, + expression=("ldapDisplayName=%s" % oc), + attrs=["possibleInferiors"]) + + poss=[] + if len(res) == 0 or res[0].get("possibleInferiors") is None: + return poss + for item in res[0]["possibleInferiors"]: + poss.append(str(item)) + poss = uniq_list(poss) + poss.sort() + return poss; + + + +# see [MS-ADTS] section 3.1.1.4.5.21 +# and section 3.1.1.4.2 for this algorithm + +# !systemOnly=TRUE +# !objectClassCategory=2 +# !objectClassCategory=3 + +def SUPCLASSES(classinfo, oc): + list = [] + if oc == "top": + return list + if classinfo[oc].get("SUPCLASSES") is not None: + return classinfo[oc]["SUPCLASSES"] + res = classinfo[oc]["subClassOf"]; + for r in res: + list.append(r) + list.extend(SUPCLASSES(classinfo,r)) + classinfo[oc]["SUPCLASSES"] = list + return list + +def AUXCLASSES(classinfo, oclist): + list = [] + if oclist == []: + return list + for oc in oclist: + if classinfo[oc].get("AUXCLASSES") is not None: + list.extend(classinfo[oc]["AUXCLASSES"]) + else: + list2 = [] + list2.extend(classinfo[oc]["systemAuxiliaryClass"]) + list2.extend(AUXCLASSES(classinfo, classinfo[oc]["systemAuxiliaryClass"])) + list2.extend(classinfo[oc]["auxiliaryClass"]) + list2.extend(AUXCLASSES(classinfo, classinfo[oc]["auxiliaryClass"])) + list2.extend(AUXCLASSES(classinfo, SUPCLASSES(classinfo, oc))) + classinfo[oc]["AUXCLASSES"] = list2 + list.extend(list2) + return list + +def SUBCLASSES(classinfo, oclist): + list = [] + for oc in oclist: + list.extend(classinfo[oc]["SUBCLASSES"]) + return list + +def POSSSUPERIORS(classinfo, oclist): + list = [] + for oc in oclist: + if classinfo[oc].get("POSSSUPERIORS") is not None: + list.extend(classinfo[oc]["POSSSUPERIORS"]) + else: + list2 = [] + list2.extend(classinfo[oc]["systemPossSuperiors"]) + list2.extend(classinfo[oc]["possSuperiors"]) + list2.extend(POSSSUPERIORS(classinfo, SUPCLASSES(classinfo, oc))) + if opts.wspp: + # the WSPP docs suggest we should do this: + list2.extend(POSSSUPERIORS(classinfo, AUXCLASSES(classinfo, [oc]))) + else: + # but testing against w2k3 and w2k8 shows that we need to do this instead + list2.extend(SUBCLASSES(classinfo, list2)) + classinfo[oc]["POSSSUPERIORS"] = list2 + list.extend(list2) + return list + +def pull_classinfo(db): + """At startup we build a classinfo[] dictionary that holds all the information needed to construct the possible inferiors""" + classinfo = {} + res = db.search(base=schema_base, + expression="objectclass=classSchema", + attrs=["ldapDisplayName", "systemOnly", "objectClassCategory", + "possSuperiors", "systemPossSuperiors", + "auxiliaryClass", "systemAuxiliaryClass", "subClassOf"]) + for r in res: + name = str(r["ldapDisplayName"][0]) + classinfo[name] = {} + if str(r["systemOnly"]) == "TRUE": + classinfo[name]["systemOnly"] = True + else: + classinfo[name]["systemOnly"] = False + if r.get("objectClassCategory"): + classinfo[name]["objectClassCategory"] = int(r["objectClassCategory"][0]) + else: + classinfo[name]["objectClassCategory"] = 0 + for a in [ "possSuperiors", "systemPossSuperiors", + "auxiliaryClass", "systemAuxiliaryClass", + "subClassOf" ]: + classinfo[name][a] = [] + if r.get(a): + for i in r[a]: + classinfo[name][a].append(str(i)) + + # build a list of subclasses for each class + def subclasses_recurse(subclasses, oc): + list = subclasses[oc] + for c in list: + list.extend(subclasses_recurse(subclasses, c)) + return list + + subclasses = {} + for oc in classinfo: + subclasses[oc] = [] + for oc in classinfo: + for c in classinfo[oc]["subClassOf"]: + if not c == oc: + subclasses[c].append(oc) + for oc in classinfo: + classinfo[oc]["SUBCLASSES"] = uniq_list(subclasses_recurse(subclasses, oc)) + + return classinfo + +def is_in_list(list, c): + for a in list: + if c == a: + return True + return False + +def possible_inferiors_constructed(db, classinfo, c): + list = [] + for oc in classinfo: + superiors = POSSSUPERIORS(classinfo, [oc]) + if (is_in_list(superiors, c) and + classinfo[oc]["systemOnly"] == False and + classinfo[oc]["objectClassCategory"] != 2 and + classinfo[oc]["objectClassCategory"] != 3): + list.append(oc) + list = uniq_list(list) + list.sort() + return list + +def test_class(db, classinfo, oc): + """test to see if one objectclass returns the correct possibleInferiors""" + print "testing objectClass %s" % oc + poss1 = possible_inferiors_search(db, oc) + poss2 = possible_inferiors_constructed(db, classinfo, oc) + if poss1 != poss2: + print "Returned incorrect list for objectclass %s" % oc + print poss1 + print poss2 + for i in range(0,min(len(poss1),len(poss2))): + print "%30s %30s" % (poss1[i], poss2[i]) + exit(1) + +def get_object_classes(db): + """return a list of all object classes""" + list=[] + for item in classinfo: + list.append(item) + return list + +classinfo = pull_classinfo(db) + +if objectclass is None: + for oc in get_object_classes(db): + test_class(db,classinfo,oc) +else: + test_class(db,classinfo,objectclass) + +print "Lists match OK" diff --git a/source4/headermap.txt b/source4/headermap.txt index 280d60beb2..1c86f9e934 100644 --- a/source4/headermap.txt +++ b/source4/headermap.txt @@ -86,6 +86,8 @@ librpc/gen_ndr/nbt.h: gen_ndr/nbt.h librpc/gen_ndr/svcctl.h: gen_ndr/svcctl.h librpc/gen_ndr/ndr_svcctl.h: gen_ndr/ndr_svcctl.h librpc/gen_ndr/ndr_svcctl_c.h: gen_ndr/ndr_svcctl_c.h +../librpc/gen_ndr/dcerpc.h: gen_ndr/dcerpc.h +../librpc/gen_ndr/ndr_dcerpc.h: gen_ndr/ndr_dcerpc.h ../librpc/gen_ndr/netlogon.h: gen_ndr/netlogon.h ../librpc/gen_ndr/ndr_misc.h: gen_ndr/ndr_misc.h ../librpc/gen_ndr/mgmt.h: gen_ndr/mgmt.h diff --git a/source4/heimdal_build/replace.c b/source4/heimdal_build/replace.c index 41309fea6e..ba43dd9495 100644 --- a/source4/heimdal_build/replace.c +++ b/source4/heimdal_build/replace.c @@ -84,3 +84,7 @@ return -1; } #endif + +const char *heimdal_version = "samba-internal-heimdal"; +const char *heimdal_long_version = "samba-interal-heimdal"; + diff --git a/source4/heimdal_build/roken.h b/source4/heimdal_build/roken.h index 3edeb2fb2e..e3edd53872 100644 --- a/source4/heimdal_build/roken.h +++ b/source4/heimdal_build/roken.h @@ -41,6 +41,22 @@ #define HAVE_STRNDUP #endif +#ifndef HAVE_STRLCPY +#define HAVE_STRLCPY +#endif + +#ifndef HAVE_STRLCAT +#define HAVE_STRLCAT +#endif + +#ifndef HAVE_STRCASECMP +#define HAVE_STRCASECMP +#endif + +#ifndef HAVE_MKSTEMP +#define HAVE_MKSTEMP +#endif + #ifndef HAVE_SETENV #define HAVE_SETENV #endif @@ -84,4 +100,7 @@ #undef SOCKET_WRAPPER_REPLACE #include "heimdal/lib/roken/roken.h.in" +extern const char *heimdal_version; +extern const char *heimdal_long_version; + #endif diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c index 1cfe9852f0..3d11441062 100644 --- a/source4/kdc/kdc.c +++ b/source4/kdc/kdc.c @@ -345,7 +345,7 @@ static bool kdc_process(struct kdc_server *kdc, } if (k5_reply.length) { *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length); - krb5_free_data_contents(kdc->smb_krb5_context->krb5_context, &k5_reply); + krb5_data_free(&k5_reply); } else { *reply = data_blob(NULL, 0); } diff --git a/source4/lib/ldb/modules/paged_searches.c b/source4/lib/ldb/modules/paged_searches.c index 01e77cb22c..c5430eb9bf 100644 --- a/source4/lib/ldb/modules/paged_searches.c +++ b/source4/lib/ldb/modules/paged_searches.c @@ -2,6 +2,7 @@ ldb database library Copyright (C) Simo Sorce 2005-2008 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -52,23 +53,40 @@ struct ps_context { char **saved_referrals; int num_referrals; + + struct ldb_request *down_req; }; -static int check_ps_continuation(struct ldb_request *req, struct ldb_reply *ares) +static int check_ps_continuation(struct ps_context *ac, struct ldb_request *req, struct ldb_reply *ares) { - struct ps_context *ac; - struct ldb_paged_control *rep_control, *req_control; + struct ldb_context *ldb; + struct ldb_control *rep_control, *req_control; + struct ldb_paged_control *paged_rep_control = NULL, *paged_req_control = NULL; + ldb = ldb_module_get_ctx(ac->module); - ac = talloc_get_type(req->context, struct ps_context); + rep_control = ldb_reply_get_control(ares, LDB_CONTROL_PAGED_RESULTS_OID); + if (rep_control) { + paged_rep_control = talloc_get_type(rep_control->data, struct ldb_paged_control); + } - /* look up our paged control */ - if (!ares->controls || strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[0]->oid) != 0) { - /* something wrong here */ - return LDB_ERR_OPERATIONS_ERROR; + req_control = ldb_request_get_control(req, LDB_CONTROL_PAGED_RESULTS_OID); + paged_req_control = talloc_get_type(req_control->data, struct ldb_paged_control); + + if (!rep_control || !paged_rep_control) { + if (paged_req_control->cookie) { + /* something wrong here - why give us a control back befre, but not one now? */ + ldb_set_errstring(ldb, "paged_searches: ERROR: We got back a control from a previous page, but this time no control was returned!"); + return LDB_ERR_OPERATIONS_ERROR; + } else { + /* No cookie recived yet, valid to just return the full data set */ + + /* we are done */ + ac->pending = false; + return LDB_SUCCESS; + } } - rep_control = talloc_get_type(ares->controls[0]->data, struct ldb_paged_control); - if (rep_control->cookie_len == 0) { + if (paged_rep_control->cookie_len == 0) { /* we are done */ ac->pending = false; return LDB_SUCCESS; @@ -79,21 +97,14 @@ static int check_ps_continuation(struct ldb_request *req, struct ldb_reply *ares /* if there's a reply control we must find a request * control matching it */ - if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, req->controls[0]->oid) != 0) { - /* something wrong here */ - return LDB_ERR_OPERATIONS_ERROR; - } - - req_control = talloc_get_type(req->controls[0]->data, struct ldb_paged_control); - - if (req_control->cookie) { - talloc_free(req_control->cookie); + if (paged_req_control->cookie) { + talloc_free(paged_req_control->cookie); } - req_control->cookie = talloc_memdup(req_control, - rep_control->cookie, - rep_control->cookie_len); - req_control->cookie_len = rep_control->cookie_len; + paged_req_control->cookie = talloc_memdup(req_control, + paged_rep_control->cookie, + paged_rep_control->cookie_len); + paged_req_control->cookie_len = paged_rep_control->cookie_len; ac->pending = true; return LDB_SUCCESS; @@ -141,8 +152,6 @@ static int send_referrals(struct ps_context *ac) return LDB_SUCCESS; } -static int ps_next_request(struct ps_context *ac); - static int ps_callback(struct ldb_request *req, struct ldb_reply *ares) { struct ps_context *ac; @@ -176,14 +185,15 @@ static int ps_callback(struct ldb_request *req, struct ldb_reply *ares) case LDB_REPLY_DONE: - ret = check_ps_continuation(req, ares); + ret = check_ps_continuation(ac, req, ares); if (ret != LDB_SUCCESS) { return ldb_module_done(ac->req, NULL, NULL, ret); } if (ac->pending) { - ret = ps_next_request(ac); + ret = ldb_next_request(ac->module, ac->down_req); + if (ret != LDB_SUCCESS) { return ldb_module_done(ac->req, NULL, NULL, ret); @@ -214,14 +224,16 @@ static int ps_search(struct ldb_module *module, struct ldb_request *req) struct ldb_context *ldb; struct private_data *private_data; struct ps_context *ac; + struct ldb_paged_control *control; + int ret; private_data = talloc_get_type(ldb_module_get_private(module), struct private_data); ldb = ldb_module_get_ctx(module); - /* check if paging is supported and if there is a any control */ - if (!private_data || !private_data->paged_supported || req->controls) { + /* check if paging is supported */ + if (!private_data || !private_data->paged_supported) { /* do not touch this request paged controls not - * supported or explicit controls have been set or we + * supported or we * are just not setup yet */ return ldb_next_request(module, req); } @@ -238,30 +250,9 @@ static int ps_search(struct ldb_module *module, struct ldb_request *req) ac->saved_referrals = NULL; ac->num_referrals = 0; - return ps_next_request(ac); -} - -static int ps_next_request(struct ps_context *ac) { - - struct ldb_context *ldb; - struct ldb_paged_control *control; - struct ldb_control **controls; - struct ldb_request *new_req; - int ret; - ldb = ldb_module_get_ctx(ac->module); - controls = talloc_array(ac, struct ldb_control *, 2); - if (!controls) { - return LDB_ERR_OPERATIONS_ERROR; - } - - controls[0] = talloc(controls, struct ldb_control); - if (!controls[0]) { - return LDB_ERR_OPERATIONS_ERROR; - } - - control = talloc(controls[0], struct ldb_paged_control); + control = talloc(ac, struct ldb_paged_control); if (!control) { return LDB_ERR_OPERATIONS_ERROR; } @@ -270,26 +261,28 @@ static int ps_next_request(struct ps_context *ac) { control->cookie = NULL; control->cookie_len = 0; - controls[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID; - controls[0]->critical = 1; - controls[0]->data = control; - controls[1] = NULL; - - ret = ldb_build_search_req_ex(&new_req, ldb, ac, + ret = ldb_build_search_req_ex(&ac->down_req, ldb, ac, ac->req->op.search.base, ac->req->op.search.scope, ac->req->op.search.tree, ac->req->op.search.attrs, - controls, + ac->req->controls, ac, ps_callback, ac->req); if (ret != LDB_SUCCESS) { return ret; } - talloc_steal(new_req, controls); - return ldb_next_request(ac->module, new_req); + ret = ldb_request_add_control(ac->down_req, LDB_CONTROL_PAGED_RESULTS_OID, + true, control); + if (ret != LDB_SUCCESS) { + return ret; + } + + talloc_steal(ac->down_req, control); + + return ldb_next_request(ac->module, ac->down_req); } static int check_supported_paged(struct ldb_request *req, diff --git a/source4/lib/ldb/pyldb.c b/source4/lib/ldb/pyldb.c index 7ff4bf4aad..bceda05e4f 100644 --- a/source4/lib/ldb/pyldb.c +++ b/source4/lib/ldb/pyldb.c @@ -5,7 +5,7 @@ Copyright (C) 2005,2006 Tim Potter <tpot@samba.org> Copyright (C) 2006 Simo Sorce <idra@samba.org> - Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org> + Copyright (C) 2007-2009 Jelmer Vernooij <jelmer@samba.org> ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -65,18 +65,7 @@ static PyObject *PyObject_FromLdbValue(struct ldb_context *ldb_ctx, PyObject *ret; new_val = *val; - - if (ldb_ctx != NULL) { - a = ldb_schema_attribute_by_name(ldb_ctx, el->name); - - if (a != NULL) { - if (a->syntax->ldif_write_fn(ldb_ctx, mem_ctx, val, &new_val) != 0) { - talloc_free(mem_ctx); - return NULL; - } - } - } - + ret = PyString_FromStringAndSize((const char *)new_val.data, new_val.length); talloc_free(mem_ctx); @@ -84,6 +73,14 @@ static PyObject *PyObject_FromLdbValue(struct ldb_context *ldb_ctx, return ret; } +/** + * Obtain a ldb DN from a Python object. + * + * @param mem_ctx Memory context + * @param object Python object + * @param ldb_ctx LDB context + * @return Whether or not the conversion succeeded + */ bool PyObject_AsDn(TALLOC_CTX *mem_ctx, PyObject *object, struct ldb_context *ldb_ctx, struct ldb_dn **dn) { @@ -104,6 +101,12 @@ bool PyObject_AsDn(TALLOC_CTX *mem_ctx, PyObject *object, return false; } +/** + * Create a Python object from a ldb_result. + * + * @param result LDB result to convert + * @return Python object with converted result (a list object) + */ static PyObject *PyLdbResult_FromResult(struct ldb_result *result) { PyObject *ret; @@ -119,7 +122,16 @@ static PyObject *PyLdbResult_FromResult(struct ldb_result *result) return ret; } -static struct ldb_result *PyLdbResult_AsResult(TALLOC_CTX *mem_ctx, PyObject *obj) +/** + * Create a LDB Result from a Python object. + * If conversion fails, NULL will be returned and a Python exception set. + * + * @param mem_ctx Memory context in which to allocate the LDB Result + * @param obj Python object to convert + * @return a ldb_result, or NULL if the conversion failed + */ +static struct ldb_result *PyLdbResult_AsResult(TALLOC_CTX *mem_ctx, + PyObject *obj) { struct ldb_result *res; int i; @@ -451,7 +463,6 @@ static PyObject *py_ldb_get_schema_basedn(PyLdbObject *self) return PyLdbDn_FromDn(dn); } - static PyObject *py_ldb_get_config_basedn(PyLdbObject *self) { struct ldb_dn *dn = ldb_get_config_basedn(PyLdb_AsLdbContext(self)); @@ -460,7 +471,6 @@ static PyObject *py_ldb_get_config_basedn(PyLdbObject *self) return PyLdbDn_FromDn(dn); } - static PyObject *py_ldb_get_default_basedn(PyLdbObject *self) { struct ldb_dn *dn = ldb_get_default_basedn(PyLdb_AsLdbContext(self)); @@ -652,8 +662,6 @@ static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args) Py_RETURN_NONE; } - - static PyObject *py_ldb_delete(PyLdbObject *self, PyObject *args) { PyObject *py_dn; @@ -1257,6 +1265,21 @@ PyTypeObject PyLdbModule = { .tp_flags = Py_TPFLAGS_DEFAULT, }; + +/** + * Create a ldb_message_element from a Python object. + * + * This will accept any sequence objects that contains strings, or + * a string object. + * + * A reference to set_obj will be borrowed. + * + * @param mem_ctx Memory context + * @param set_obj Python object to convert + * @param flags ldb_message_element flags to set + * @param attr_name Name of the attribute + * @return New ldb_message_element, allocated as child of mem_ctx + */ struct ldb_message_element *PyObject_AsMessageElement(TALLOC_CTX *mem_ctx, PyObject *set_obj, int flags, const char *attr_name) @@ -1274,9 +1297,7 @@ struct ldb_message_element *PyObject_AsMessageElement(TALLOC_CTX *mem_ctx, me->num_values = 1; me->values = talloc_array(me, struct ldb_val, me->num_values); me->values[0].length = PyString_Size(set_obj); - me->values[0].data = (uint8_t *)talloc_strndup(me->values, - PyString_AsString(set_obj), - me->values[0].length); + me->values[0].data = (uint8_t *)PyString_AsString(set_obj); } else if (PySequence_Check(set_obj)) { int i; me->num_values = PySequence_Size(set_obj); diff --git a/source4/lib/ldb/tests/python/api.py b/source4/lib/ldb/tests/python/api.py index c372b8fa71..07500e2372 100755 --- a/source4/lib/ldb/tests/python/api.py +++ b/source4/lib/ldb/tests/python/api.py @@ -258,6 +258,19 @@ class SimpleLdb(unittest.TestCase): l = ldb.Ldb(filename()) l.set_debug(my_report_fn) + def test_zero_byte_string(self): + """Testing we do not get trapped in the \0 byte in a property string.""" + l = ldb.Ldb(filename()) + l.add({ + "dn" : "dc=somedn", + "objectclass" : "user", + "cN" : "LDAPtestUSER", + "givenname" : "ldap", + "displayname" : "foo\0bar", + }) + res = l.search(expression="(dn=dc=somedn)") + self.assertEquals("foo\0bar", res[0]["displayname"][0]) + class DnTests(unittest.TestCase): def setUp(self): diff --git a/source4/lib/smbreadline/smbreadline.c b/source4/lib/smbreadline/smbreadline.c index 5fb3bf4fae..b07417357f 100644 --- a/source4/lib/smbreadline/smbreadline.c +++ b/source4/lib/smbreadline/smbreadline.c @@ -83,6 +83,7 @@ static char *smb_readline_replacement(const char *prompt, void (*callback)(void) char *ret; printf("%s", prompt); + fflush(stdout); line = (char *)malloc(BUFSIZ); if (!line) { diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h index a0584c0aa4..bd93fa1695 100644 --- a/source4/libcli/raw/interfaces.h +++ b/source4/libcli/raw/interfaces.h @@ -53,6 +53,16 @@ struct smb2_handle { uint64_t data[2]; }; +/* + SMB2 lease structure (per MS-SMB2 2.2.13) +*/ +struct smb2_lease { + uint64_t lease_key[2]; + uint32_t lease_state; + uint32_t lease_flags; /* should be 0 */ + uint64_t lease_duration; /* should be 0 */ +}; + struct ntvfs_handle; /* @@ -1633,6 +1643,7 @@ union smb_open { bool query_maximal_access; NTTIME timewarp; bool query_on_disk_id; + struct smb2_lease *lease_request; /* and any additional blobs the caller wants */ struct smb2_create_blobs { @@ -1666,6 +1677,7 @@ union smb_open { /* optional return values matching tagged values in the call */ uint32_t maximal_access; uint8_t on_disk_id[32]; + struct smb2_lease lease_response; /* tagged blobs in the reply */ struct smb2_create_blobs blobs; diff --git a/source4/libcli/security/config.mk b/source4/libcli/security/config.mk index d6d9ad5545..9d23fe9588 100644 --- a/source4/libcli/security/config.mk +++ b/source4/libcli/security/config.mk @@ -4,7 +4,5 @@ PUBLIC_DEPENDENCIES = LIBNDR LIBSECURITY_COMMON LIBSECURITY_OBJ_FILES = $(addprefix $(libclisrcdir)/security/, \ security_token.o security_descriptor.o \ access_check.o privilege.o sddl.o) \ - ../libcli/security/secace.o \ - ../libcli/security/secacl.o $(eval $(call proto_header_template,$(libclisrcdir)/security/proto.h,$(LIBSECURITY_OBJ_FILES:.o=.c))) diff --git a/source4/libcli/smb2/create.c b/source4/libcli/smb2/create.c index 8a40e56a00..344be60f6e 100644 --- a/source4/libcli/smb2/create.c +++ b/source4/libcli/smb2/create.c @@ -312,6 +312,23 @@ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create } } + if (io->in.lease_request) { + uint8_t data[32]; + + memcpy(&data[0], io->in.lease_request->lease_key, 16); + SIVAL(data, 16, io->in.lease_request->lease_state); + SIVAL(data, 20, io->in.lease_request->lease_flags); + SBVAL(data, 24, io->in.lease_request->lease_duration); + + status = smb2_create_blob_add(req, &blobs, + SMB2_CREATE_TAG_RQLS, + data_blob_const(data, 32)); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(req); + return NULL; + } + } + /* and any custom blobs */ for (i=0;i<io->in.blobs.num_blobs;i++) { status = smb2_create_blob_add(req, &blobs, @@ -402,6 +419,19 @@ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct } memcpy(io->out.on_disk_id, io->out.blobs.blobs[i].data.data, 32); } + if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_RQLS) == 0) { + uint8_t *data; + if (io->out.blobs.blobs[i].data.length != 32) { + smb2_request_destroy(req); + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + data = io->out.blobs.blobs[i].data.data; + memcpy(io->out.lease_response.lease_key, data, 16); + io->out.lease_response.lease_state = IVAL(data, 16); + io->out.lease_response.lease_flags = IVAL(data, 20); + io->out.lease_response.lease_duration = BVAL(data, 24); + } } data_blob_free(&blob); diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h index 7c07c84740..fd961ce5f3 100644 --- a/source4/libcli/smb2/smb2.h +++ b/source4/libcli/smb2/smb2.h @@ -263,6 +263,13 @@ struct smb2_request { #define SMB2_OPLOCK_LEVEL_II 0x01 #define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 #define SMB2_OPLOCK_LEVEL_BATCH 0x09 +#define SMB2_OPLOCK_LEVEL_LEASE 0xFF + +/* SMB2 lease bits */ +#define SMB2_LEASE_NONE 0x00 +#define SMB2_LEASE_READ 0x01 +#define SMB2_LEASE_HANDLE 0x02 +#define SMB2_LEASE_WRITE 0x04 /* SMB2 impersonation levels */ #define SMB2_IMPERSONATION_ANONYMOUS 0x00 @@ -279,6 +286,7 @@ struct smb2_request { #define SMB2_CREATE_TAG_ALSI "AlSi" #define SMB2_CREATE_TAG_TWRP "TWrp" #define SMB2_CREATE_TAG_QFID "QFid" +#define SMB2_CREATE_TAG_RQLS "RqLs" /* SMB2 Create ignore some more create_options */ #define SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK (NTCREATEX_OPTIONS_TREE_CONNECTION | \ diff --git a/source4/librpc/config.mk b/source4/librpc/config.mk index 2f1b14dc37..64a4750ab7 100644 --- a/source4/librpc/config.mk +++ b/source4/librpc/config.mk @@ -595,9 +595,9 @@ RPC_NDR_KEYSVC_OBJ_FILES = ../librpc/gen_ndr/ndr_keysvc_c.o [SUBSYSTEM::NDR_DCERPC] PUBLIC_DEPENDENCIES = LIBNDR -NDR_DCERPC_OBJ_FILES = $(gen_ndrsrcdir)/ndr_dcerpc.o +NDR_DCERPC_OBJ_FILES = ../librpc/gen_ndr/ndr_dcerpc.o -PUBLIC_HEADERS += $(addprefix $(librpcsrcdir)/, gen_ndr/dcerpc.h gen_ndr/ndr_dcerpc.h) +PUBLIC_HEADERS += ../librpc/gen_ndr/dcerpc.h ../librpc/gen_ndr/ndr_dcerpc.h ################################################ # Start SUBSYSTEM dcerpc diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl deleted file mode 100644 index 7c0abe6ab8..0000000000 --- a/source4/librpc/idl/dcerpc.idl +++ /dev/null @@ -1,306 +0,0 @@ -#include "idl_types.h" - -/* - the base dcerpc packet definitions - not traditionally coded as IDL, - but given that pidl can handle it nicely it simplifies things a lot - to do it this way - - see http://www.opengroup.org/onlinepubs/9629399/chap12.htm for packet - layouts -*/ -import "misc.idl"; - -interface dcerpc -{ - typedef struct { - uint16 context_id; - uint8 num_transfer_syntaxes; - ndr_syntax_id abstract_syntax; - ndr_syntax_id transfer_syntaxes[num_transfer_syntaxes]; - } dcerpc_ctx_list; - - typedef struct { - uint16 max_xmit_frag; - uint16 max_recv_frag; - uint32 assoc_group_id; - uint8 num_contexts; - dcerpc_ctx_list ctx_list[num_contexts]; - [flag(NDR_ALIGN4)] DATA_BLOB _pad; - [flag(NDR_REMAINING)] DATA_BLOB auth_info; - } dcerpc_bind; - - const uint8 DCERPC_REQUEST_LENGTH = 24; - - typedef struct { - } dcerpc_empty; - - typedef [nodiscriminant] union { - [default] dcerpc_empty empty; - [case(LIBNDR_FLAG_OBJECT_PRESENT)] GUID object; - } dcerpc_object; - - typedef struct { - uint32 alloc_hint; - uint16 context_id; - uint16 opnum; - [switch_is(ndr->flags & LIBNDR_FLAG_OBJECT_PRESENT)] dcerpc_object object; - [flag(NDR_ALIGN8)] DATA_BLOB _pad; - [flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier; - } dcerpc_request; - - const int DCERPC_BIND_REASON_ASYNTAX = 1; - const int DCERPC_BIND_PROVIDER_REJECT = 2; - const int DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED = 4; - const int DCERPC_BIND_REASON_INVALID_AUTH_TYPE = 8; - - typedef struct { - uint16 result; - uint16 reason; - ndr_syntax_id syntax; - } dcerpc_ack_ctx; - - typedef struct { - uint16 max_xmit_frag; - uint16 max_recv_frag; - uint32 assoc_group_id; - [value(strlen(secondary_address)+1)] uint16 secondary_address_size; - [charset(DOS)] uint8 secondary_address[secondary_address_size]; - [flag(NDR_ALIGN4)] DATA_BLOB _pad1; - uint8 num_results; - dcerpc_ack_ctx ctx_list[num_results]; - [flag(NDR_REMAINING)] DATA_BLOB auth_info; - } dcerpc_bind_ack; - - typedef struct { - uint32 num_versions; - uint32 versions[num_versions]; - } dcerpc_bind_nak_versions; - - typedef [nodiscriminant] union { - [case(DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED)] dcerpc_bind_nak_versions v; - [default] ; - } dcerpc_bind_nak_versions_ctr; - - typedef struct { - uint16 reject_reason; - [switch_is(reject_reason)] dcerpc_bind_nak_versions_ctr versions; - } dcerpc_bind_nak; - - const uint8 DCERPC_RESPONSE_LENGTH = 24; - - typedef struct { - uint32 alloc_hint; - uint16 context_id; - uint8 cancel_count; - [flag(NDR_ALIGN8)] DATA_BLOB _pad; - [flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier; - } dcerpc_response; - - - const int DCERPC_FAULT_OP_RNG_ERROR = 0x1c010002; - const int DCERPC_FAULT_UNK_IF = 0x1c010003; - const int DCERPC_FAULT_NDR = 0x000006f7; - const int DCERPC_FAULT_INVALID_TAG = 0x1c000006; - const int DCERPC_FAULT_CONTEXT_MISMATCH = 0x1c00001a; - const int DCERPC_FAULT_OTHER = 0x00000001; - const int DCERPC_FAULT_ACCESS_DENIED = 0x00000005; - const int DCERPC_FAULT_CANT_PERFORM = 0x000006d8; - - /* we return this fault when we haven't yet run the test - to see what fault w2k3 returns in this case */ - const int DCERPC_FAULT_TODO = 0x00000042; - - typedef struct { - uint32 alloc_hint; - uint16 context_id; - uint8 cancel_count; - uint32 status; - [flag(NDR_REMAINING)] DATA_BLOB _pad; - } dcerpc_fault; - - /* the auth types we know about */ - typedef [enum8bit] enum { - DCERPC_AUTH_TYPE_NONE = 0, - /* this seems to be not krb5! */ - DCERPC_AUTH_TYPE_KRB5_1 = 1, - DCERPC_AUTH_TYPE_SPNEGO = 9, - DCERPC_AUTH_TYPE_NTLMSSP = 10, - DCERPC_AUTH_TYPE_KRB5 = 16, - DCERPC_AUTH_TYPE_DPA = 17, - DCERPC_AUTH_TYPE_MSN = 18, - DCERPC_AUTH_TYPE_DIGEST = 21, - DCERPC_AUTH_TYPE_SCHANNEL = 68, - DCERPC_AUTH_TYPE_MSMQ = 100 - } dcerpc_AuthType; - - typedef [enum8bit] enum { - DCERPC_AUTH_LEVEL_NONE = 1, - DCERPC_AUTH_LEVEL_CONNECT = 2, - DCERPC_AUTH_LEVEL_CALL = 3, - DCERPC_AUTH_LEVEL_PACKET = 4, - DCERPC_AUTH_LEVEL_INTEGRITY = 5, - DCERPC_AUTH_LEVEL_PRIVACY = 6 - } dcerpc_AuthLevel; - - const uint8 DCERPC_AUTH_LEVEL_DEFAULT = DCERPC_AUTH_LEVEL_CONNECT; - - typedef [public] struct { - dcerpc_AuthType auth_type; - dcerpc_AuthLevel auth_level; - uint8 auth_pad_length; - uint8 auth_reserved; - uint32 auth_context_id; - [flag(NDR_REMAINING)] DATA_BLOB credentials; - } dcerpc_auth; - - const uint8 DCERPC_AUTH_TRAILER_LENGTH = 8; - - typedef [public] struct { - uint32 _pad; - [flag(NDR_REMAINING)] DATA_BLOB auth_info; - } dcerpc_auth3; - - typedef [public] struct { - uint32 _pad; - [flag(NDR_REMAINING)] DATA_BLOB auth_info; - } dcerpc_orphaned; - - typedef [public] struct { - uint32 _pad; - [flag(NDR_REMAINING)] DATA_BLOB auth_info; - } dcerpc_co_cancel; - - typedef [public] struct { - uint32 version; - uint32 id; - } dcerpc_cl_cancel; - - typedef [public] struct { - uint32 version; - uint32 id; - boolean32 server_is_accepting; - } dcerpc_cancel_ack; - - typedef [public] struct { - uint32 version; - uint8 _pad1; - uint16 window_size; - uint32 max_tdsu; - uint32 max_frag_size; - uint16 serial_no; - uint16 selack_size; - uint32 selack[selack_size]; - } dcerpc_fack; - - typedef [public] struct { - } dcerpc_ack; - - typedef [public] struct { - } dcerpc_ping; - - typedef [public] struct { - } dcerpc_shutdown; - - typedef [public] struct { - } dcerpc_working; - - typedef [enum8bit] enum { - DCERPC_PKT_REQUEST = 0, /* Ordinary request. */ - DCERPC_PKT_PING = 1, /* Connectionless is server alive ? */ - DCERPC_PKT_RESPONSE = 2, /* Ordinary reply. */ - DCERPC_PKT_FAULT = 3, /* Fault in processing of call. */ - DCERPC_PKT_WORKING = 4, /* Connectionless reply to a ping when server busy. */ - DCERPC_PKT_NOCALL = 5, /* Connectionless reply to a ping when server has lost part of clients call. */ - DCERPC_PKT_REJECT = 6, /* Refuse a request with a code. */ - DCERPC_PKT_ACK = 7, /* Connectionless client to server code. */ - DCERPC_PKT_CL_CANCEL = 8, /* Connectionless cancel. */ - DCERPC_PKT_FACK = 9, /* Connectionless fragment ack. Both client and server send. */ - DCERPC_PKT_CANCEL_ACK = 10, /* Server ACK to client cancel request. */ - DCERPC_PKT_BIND = 11, /* Bind to interface. */ - DCERPC_PKT_BIND_ACK = 12, /* Server ack of bind. */ - DCERPC_PKT_BIND_NAK = 13, /* Server nack of bind. */ - DCERPC_PKT_ALTER = 14, /* Alter auth. */ - DCERPC_PKT_ALTER_RESP = 15, /* Reply to alter auth. */ - DCERPC_PKT_AUTH3 = 16, /* not the real name! this is undocumented! */ - DCERPC_PKT_SHUTDOWN = 17, /* Server to client request to shutdown. */ - DCERPC_PKT_CO_CANCEL = 18, /* Connection-oriented cancel request. */ - DCERPC_PKT_ORPHANED = 19 /* Client telling server it's aborting a partially sent request or telling server to stop sending replies. */ - } dcerpc_pkt_type; - - typedef [nodiscriminant] union { - [case(DCERPC_PKT_REQUEST)] dcerpc_request request; - [case(DCERPC_PKT_PING)] dcerpc_ping ping; - [case(DCERPC_PKT_RESPONSE)] dcerpc_response response; - [case(DCERPC_PKT_FAULT)] dcerpc_fault fault; - [case(DCERPC_PKT_WORKING)] dcerpc_working working; - [case(DCERPC_PKT_NOCALL)] dcerpc_fack nocall; - [case(DCERPC_PKT_REJECT)] dcerpc_fault reject; - [case(DCERPC_PKT_ACK)] dcerpc_ack ack; - [case(DCERPC_PKT_CL_CANCEL)] dcerpc_cl_cancel cl_cancel; - [case(DCERPC_PKT_FACK)] dcerpc_fack fack; - [case(DCERPC_PKT_CANCEL_ACK)] dcerpc_cancel_ack cancel_ack; - [case(DCERPC_PKT_BIND)] dcerpc_bind bind; - [case(DCERPC_PKT_BIND_ACK)] dcerpc_bind_ack bind_ack; - [case(DCERPC_PKT_BIND_NAK)] dcerpc_bind_nak bind_nak; - [case(DCERPC_PKT_ALTER)] dcerpc_bind alter; - [case(DCERPC_PKT_ALTER_RESP)] dcerpc_bind_ack alter_resp; - [case(DCERPC_PKT_SHUTDOWN)] dcerpc_shutdown shutdown; - [case(DCERPC_PKT_CO_CANCEL)] dcerpc_co_cancel co_cancel; - [case(DCERPC_PKT_ORPHANED)] dcerpc_orphaned orphaned; - [case(DCERPC_PKT_AUTH3)] dcerpc_auth3 auth3; - } dcerpc_payload; - - /* pfc_flags values */ - const uint8 DCERPC_PFC_FLAG_FIRST = 0x01; /* First fragment */ - const uint8 DCERPC_PFC_FLAG_LAST = 0x02; /* Last fragment */ - const uint8 DCERPC_PFC_FLAG_PENDING_CANCEL = 0x04; /* Cancel was pending at sender */ - const uint8 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN = DCERPC_PFC_FLAG_PENDING_CANCEL; /* depends on the pdu type */ - const uint8 DCERPC_PFC_FLAG_CONC_MPX = 0x10; /* supports concurrent multiplexing of a single connection. */ - const uint8 DCERPC_PFC_FLAG_DID_NOT_EXECUTE = 0x20; /* on a fault it means the server hasn't done anything */ - const uint8 DCERPC_PFC_FLAG_MAYBE = 0x40; /* `maybe' call semantics requested */ - const uint8 DCERPC_PFC_FLAG_OBJECT_UUID = 0x80; /* on valid guid is in the optional object field */ - - /* these offsets are needed by the signing code */ - const uint8 DCERPC_PFC_OFFSET = 3; - const uint8 DCERPC_DREP_OFFSET = 4; - const uint8 DCERPC_FRAG_LEN_OFFSET = 8; - const uint8 DCERPC_AUTH_LEN_OFFSET = 10; - - /* little-endian flag */ - const uint8 DCERPC_DREP_LE = 0x10; - - typedef [public] struct { - uint8 rpc_vers; /* RPC version */ - uint8 rpc_vers_minor; /* Minor version */ - dcerpc_pkt_type ptype; /* Packet type */ - uint8 pfc_flags; /* Fragmentation flags */ - uint8 drep[4]; /* NDR data representation */ - uint16 frag_length; /* Total length of fragment */ - uint16 auth_length; /* authenticator length */ - uint32 call_id; /* Call identifier */ - [switch_is(ptype)] dcerpc_payload u; - } ncacn_packet; - - typedef [public] struct { - uint8 rpc_vers; /* RPC version (4) */ - uint8 ptype; - uint8 pfc_flags; - uint8 ncadg_flags; - uint8 drep[3]; - uint8 serial_high; - GUID object; - GUID iface; - GUID activity; - uint32 server_boot; /* Server boot time */ - uint32 iface_version; - uint32 seq_num; - uint16 opnum; - uint16 ihint; - uint16 ahint; - uint16 len; - uint16 fragnum; - uint8 auth_proto; - uint8 serial_low; - [switch_is(ptype)] dcerpc_payload u; - } ncadg_packet; -} diff --git a/source4/main.mk b/source4/main.mk index a143604f33..d7db0580e9 100644 --- a/source4/main.mk +++ b/source4/main.mk @@ -46,6 +46,7 @@ mkinclude torture/config.mk mkinclude librpc/config.mk mkinclude client/config.mk mkinclude libcli/config.mk +mkinclude ../libcli/cldap/config.mk mkinclude scripting/python/config.mk mkinclude kdc/config.mk mkinclude ../lib/smbconf/config.mk diff --git a/source4/min_versions.m4 b/source4/min_versions.m4 index eaefbd5148..1dd3501b99 100644 --- a/source4/min_versions.m4 +++ b/source4/min_versions.m4 @@ -1,6 +1,6 @@ # Minimum and exact required versions for various libraries # if we use the ones installed in the system. -TDB_MIN_VERSION=1.1.3 -TALLOC_MIN_VERSION=1.3.0 -LDB_REQUIRED_VERSION=0.9.3 -TEVENT_REQUIRED_VERSION=0.9.5 +define(TDB_MIN_VERSION,1.1.3) +define(TALLOC_MIN_VERSION,1.3.0) +define(LDB_REQUIRED_VERSION,0.9.3) +define(TEVENT_REQUIRED_VERSION,0.9.5) diff --git a/source4/script/uninstallman.sh b/source4/script/uninstallman.sh index 9b087c68bb..edc1c47e4d 100755 --- a/source4/script/uninstallman.sh +++ b/source4/script/uninstallman.sh @@ -8,7 +8,7 @@ MANPAGES=$* for I in $MANPAGES do - SECTION=`echo -n $I | sed "s/.*\(.\)$/\1/" + SECTION=`echo -n $I | sed "s/.*\(.\)$/\1/"` FNAME=$MANDIR/man$SECTION/$I if test -f $FNAME; then echo Deleting $FNAME diff --git a/source4/scripting/bin/fullschema b/source4/scripting/bin/fullschema new file mode 100644 index 0000000000..41c45f30c8 --- /dev/null +++ b/source4/scripting/bin/fullschema @@ -0,0 +1,179 @@ +#!/usr/bin/python +# +# work out the minimal schema for a set of objectclasses +# + +import base64 +import optparse +import os +import sys + +# Find right directory when running from source tree +sys.path.insert(0, "bin/python") + +import samba +from samba import getopt as options, Ldb +from ldb import SCOPE_SUBTREE, SCOPE_BASE, LdbError +import sys + +parser = optparse.OptionParser("fullschema <URL>") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) +credopts = options.CredentialsOptions(parser) +parser.add_option_group(credopts) +parser.add_option_group(options.VersionOptions(parser)) +parser.add_option("--dump-classes", action="store_true") +parser.add_option("--dump-attributes", action="store_true") + +opts, args = parser.parse_args() +opts.dump_all = True + +if opts.dump_classes: + opts.dump_all = False +if opts.dump_attributes: + opts.dump_all = False +if opts.dump_all: + opts.dump_classes = True + opts.dump_attributes = True + +if len(args) != 1: + parser.print_usage() + sys.exit(1) + +url = args[0] + +lp_ctx = sambaopts.get_loadparm() + +creds = credopts.get_credentials(lp_ctx) +ldb = Ldb(url, credentials=creds, lp=lp_ctx, options=["modules:paged_searches"]) + +# the attributes we need for objectclasses +class_attrs = ["objectClass", + "cn", + "subClassOf", + "governsID", + "possSuperiors", + "possibleInferiors", + "mayContain", + "mustContain", + "auxiliaryClass", + "rDNAttID", + "adminDisplayName", + "adminDescription", + "objectClassCategory", + "lDAPDisplayName", + "schemaIDGUID", + "systemOnly", + "systemPossSuperiors", + "systemMayContain", + "systemMustContain", + "systemAuxiliaryClass", + "defaultSecurityDescriptor", + "systemFlags", + "defaultHidingValue", + "defaultObjectCategory", + + # this attributes are not used by w2k3 + "schemaFlagsEx", + "msDs-IntId", + "msDs-Schema-Extensions", + "classDisplayName", + "isDefunct"] + +attrib_attrs = ["objectClass", + "cn", + "attributeID", + "attributeSyntax", + "isSingleValued", + "rangeLower", + "rangeUpper", + "mAPIID", + "linkID", + "adminDisplayName", + "oMObjectClass", + "adminDescription", + "oMSyntax", + "searchFlags", + "extendedCharsAllowed", + "lDAPDisplayName", + "schemaIDGUID", + "attributeSecurityGUID", + "systemOnly", + "systemFlags", + "isMemberOfPartialAttributeSet", + + # this attributes are not used by w2k3 + "schemaFlagsEx", + "msDs-IntId", + "msDs-Schema-Extensions", + "classDisplayName", + "isEphemeral", + "isDefunct"] + +class Objectclass(dict): + + def __init__(self, ldb, name): + """create an objectclass object""" + self.name = name + + +class Attribute(dict): + + def __init__(self, ldb, name): + """create an attribute object""" + self.name = name + self["cn"] = get_object_cn(ldb, name) + + + +def fix_dn(dn): + """fix a string DN to use ${SCHEMADN}""" + return dn.replace(rootDse["schemaNamingContext"][0], "${SCHEMADN}") + + +def write_ldif_one(o, attrs): + """dump an object as ldif""" + print "dn: CN=%s,${SCHEMADN}" % o["cn"] + for a in attrs: + if not o.has_key(a): + continue + # special case for oMObjectClass, which is a binary object + v = o[a] + for j in v: + value = fix_dn(j) + if a != "cn": + if a == "oMObjectClass": + print "%s:: %s" % (a, base64.b64encode(value)) + elif a.endswith("GUID"): + print "%s: %s" % (a, ldb.schema_format_value(a, value)) + else: + print "%s: %s" % (a, value) + print "" + + +# get the rootDSE +res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"]) +rootDse = res[0] + +if opts.dump_attributes: + res = ldb.search(expression="objectClass=attributeSchema", + base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE,attrs=attrib_attrs, + controls=["server_sort:1:0:cn"]) + + for msg in res: + o = Objectclass(ldb, msg["ldapDisplayName"]) + for a in msg: + o[a] = msg[a] + write_ldif_one(o, attrib_attrs) + +if opts.dump_classes: + res = ldb.search(expression="objectClass=classSchema", + base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE,attrs=class_attrs, + controls=["server_sort:1:0:cn"]) + + for msg in res: + o = Objectclass(ldb, msg["ldapDisplayName"]) + for a in msg: + o[a] = msg[a] + write_ldif_one(o, class_attrs) + diff --git a/source4/scripting/bin/minschema b/source4/scripting/bin/minschema index f2dfdcb564..c860495e96 100755 --- a/source4/scripting/bin/minschema +++ b/source4/scripting/bin/minschema @@ -72,7 +72,6 @@ class_attrs = ["objectClass", "mustContain", "auxiliaryClass", "rDNAttID", - "showInAdvancedViewOnly", "adminDisplayName", "adminDescription", "objectClassCategory", @@ -104,7 +103,6 @@ attrib_attrs = ["objectClass", "rangeUpper", "mAPIID", "linkID", - "showInAdvancedViewOnly", "adminDisplayName", "oMObjectClass", "adminDescription", @@ -405,40 +403,40 @@ def attribute_list(objectclass, attr1, attr2): def aggregate_list(name, list): """write out a list in aggregate form""" - if list is None: - return - print "%s ( %s )" % (name, "$ ".join(list)) + if list == []: + return "" + return " %s ( %s )" % (name, " $ ".join(list)) def write_aggregate_objectclass(objectclass): """write the aggregate record for an objectclass""" - print "objectClasses: ( %s NAME '%s' " % (objectclass["governsID"], objectclass.name), + line = "objectClasses: ( %s NAME '%s' " % (objectclass["governsID"], objectclass.name) if not objectclass.has_key('subClassOf'): - print "SUP %s " % objectclass['subClassOf'], + line += "SUP %s" % objectclass['subClassOf'] if objectclass["objectClassCategory"] == 1: - print "STRUCTURAL ", + line += "STRUCTURAL" elif objectclass["objectClassCategory"] == 2: - print "ABSTRACT ", + line += "ABSTRACT" elif objectclass["objectClassCategory"] == 3: - print "AUXILIARY ", + line += "AUXILIARY" list = attribute_list(objectclass, "systemMustContain", "mustContain") - aggregate_list("MUST", list) + line += aggregate_list("MUST", list) list = attribute_list(objectclass, "systemMayContain", "mayContain") - aggregate_list("MAY", list) + line += aggregate_list("MAY", list) - print ")" + print line + " )" def write_aggregate_ditcontentrule(objectclass): """write the aggregate record for an ditcontentrule""" list = attribute_list(objectclass, "auxiliaryClass", "systemAuxiliaryClass") - if list is None: + if list == []: return - print "dITContentRules: ( %s NAME '%s' " % (objectclass["governsID"], objectclass.name) + line = "dITContentRules: ( %s NAME '%s'" % (objectclass["governsID"], objectclass.name) - aggregate_list("AUX", list) + line += aggregate_list("AUX", list) may_list = [] must_list = [] @@ -451,31 +449,30 @@ def write_aggregate_ditcontentrule(objectclass): "mustContain", "systemMustContain") must_list = must_list + list2 - aggregate_list("MUST", must_list) - aggregate_list("MAY", may_list) + line += aggregate_list("MUST", must_list) + line += aggregate_list("MAY", may_list) - print ")\n" + print line + " )" def write_aggregate_attribute(attrib): """write the aggregate record for an attribute""" - print "attributeTypes: ( %s NAME '%s' SYNTAX '%s' " % ( + line = "attributeTypes: ( %s NAME '%s' SYNTAX '%s' " % ( attrib["attributeID"], attrib.name, map_attribute_syntax(attrib["attributeSyntax"])) if attrib.get('isSingleValued') == "TRUE": - print "SINGLE-VALUE " + line += "SINGLE-VALUE " if attrib.get('systemOnly') == "TRUE": - print "NO-USER-MODIFICATION " + line += "NO-USER-MODIFICATION " - print ")\n" + print line + ")" def write_aggregate(): """write the aggregate record""" - print "dn: CN=Aggregate,${SCHEMADN}\n" + print "dn: CN=Aggregate,${SCHEMADN}" print """objectClass: top objectClass: subSchema -objectCategory: CN=SubSchema,${SCHEMADN} -""" +objectCategory: CN=SubSchema,${SCHEMADN}""" if not opts.dump_subschema_auto: return diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index a49e6e1ead..c5827b96e0 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -54,7 +54,7 @@ class Ldb(ldb.Ldb): functions see samdb.py. """ def __init__(self, url=None, session_info=None, credentials=None, - modules_dir=None, lp=None): + modules_dir=None, lp=None, options=None): """Open a Samba Ldb file. :param url: Optional LDB URL to open @@ -67,7 +67,7 @@ class Ldb(ldb.Ldb): modules-dir is used by default and that credentials and session_info can be passed through (required by some modules). """ - super(Ldb, self).__init__() + super(Ldb, self).__init__(options=options) if modules_dir is not None: self.set_modules_dir(modules_dir) @@ -90,7 +90,7 @@ class Ldb(ldb.Ldb): #self.set_debug(msg) if url is not None: - self.connect(url) + self.connect(url, options=options) def set_credentials(self, credentials): glue.ldb_set_credentials(self, credentials) diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 1e34b11d0a..64908ccb4d 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1051,7 +1051,7 @@ def provision(setup_dir, message, session_info, serverrole=serverrole, ldap_backend=ldap_backend, ldap_backend_type=ldap_backend_type) - if lp.get("server role") == "domain controller": + if serverrole == "domain controller": if paths.netlogon is None: message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.") message("Please either remove %s or see the template at %s" % diff --git a/source4/selftest/config.mk b/source4/selftest/config.mk index 324532c22a..1838a0bb38 100644 --- a/source4/selftest/config.mk +++ b/source4/selftest/config.mk @@ -59,31 +59,31 @@ test-%:: valgrindtest:: valgrindtest-all valgrindtest-quick:: all - SMBD_VALGRIND="xterm -n server -e $(selftestdir)/valgrind_run $(LD_LIBPATH_OVERRIDE)" \ + SAMBA_VALGRIND="xterm -n server -e $(selftestdir)/valgrind_run $(LD_LIBPATH_OVERRIDE)" \ VALGRIND="valgrind -q --num-callers=30 --log-file=${selftest_prefix}/valgrind.log" \ $(SELFTEST) $(SELFTEST_QUICK_OPTS) --immediate --socket-wrapper $(TESTS) valgrindtest-all:: everything - SMBD_VALGRIND="xterm -n server -e $(selftestdir)/valgrind_run $(LD_LIBPATH_OVERRIDE)" \ + SAMBA_VALGRIND="xterm -n server -e $(selftestdir)/valgrind_run $(LD_LIBPATH_OVERRIDE)" \ VALGRIND="valgrind -q --num-callers=30 --log-file=${selftest_prefix}/valgrind.log" \ $(SELFTEST) $(SELFTEST_NOSLOW_OPTS) --immediate --socket-wrapper $(TESTS) valgrindtest-env:: everything - SMBD_VALGRIND="xterm -n server -e $(selftestdir)/valgrind_run $(LD_LIBPATH_OVERRIDE)" \ + SAMBA_VALGRIND="xterm -n server -e $(selftestdir)/valgrind_run $(LD_LIBPATH_OVERRIDE)" \ VALGRIND="valgrind -q --num-callers=30 --log-file=${selftest_prefix}/valgrind.log" \ $(SELFTEST) $(SELFTEST_NOSLOW_OPTS) --socket-wrapper --testenv gdbtest:: gdbtest-all gdbtest-quick:: all - SMBD_VALGRIND="xterm -n server -e $(selftestdir)/gdb_run $(LD_LIBPATH_OVERRIDE)" \ + SAMBA_VALGRIND="xterm -n server -e $(selftestdir)/gdb_run $(LD_LIBPATH_OVERRIDE)" \ $(SELFTEST) $(SELFTEST_QUICK_OPTS) --immediate --socket-wrapper $(TESTS) gdbtest-all:: everything - SMBD_VALGRIND="xterm -n server -e $(selftestdir)/gdb_run $(LD_LIBPATH_OVERRIDE)" \ + SAMBA_VALGRIND="xterm -n server -e $(selftestdir)/gdb_run $(LD_LIBPATH_OVERRIDE)" \ $(SELFTEST) $(SELFTEST_NOSLOW_OPTS) --immediate --socket-wrapper $(TESTS) gdbtest-env:: everything - SMBD_VALGRIND="xterm -n server -e $(selftestdir)/gdb_run $(LD_LIBPATH_OVERRIDE)" \ + SAMBA_VALGRIND="xterm -n server -e $(selftestdir)/gdb_run $(LD_LIBPATH_OVERRIDE)" \ $(SELFTEST) $(SELFTEST_NOSLOW_OPTS) --socket-wrapper --testenv diff --git a/source4/smbd/server.c b/source4/smbd/server.c index d576782ab1..635e84fafe 100644 --- a/source4/smbd/server.c +++ b/source4/smbd/server.c @@ -365,5 +365,5 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[ int main(int argc, const char *argv[]) { - return binary_smbd_main("smbd", argc, argv); + return binary_smbd_main("samba", argc, argv); } diff --git a/source4/torture/ldap/cldap.c b/source4/torture/ldap/cldap.c index 98669288a8..814c9ac86d 100644 --- a/source4/torture/ldap/cldap.c +++ b/source4/torture/ldap/cldap.c @@ -59,8 +59,8 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest) CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(search); - search.in.dest_address = NULL;//dest; - search.in.dest_port = 0;//lp_cldap_port(tctx->lp_ctx); + search.in.dest_address = NULL; + search.in.dest_port = 0; search.in.acct_control = -1; search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; search.in.map_response = true; diff --git a/source4/torture/smb2/config.mk b/source4/torture/smb2/config.mk index e0fc29f278..70b1743929 100644 --- a/source4/torture/smb2/config.mk +++ b/source4/torture/smb2/config.mk @@ -20,8 +20,9 @@ TORTURE_SMB2_OBJ_FILES = $(addprefix $(torturesrcdir)/smb2/, \ lock.o \ notify.o \ smb2.o \ - persistent_handles.o \ + durable_open.o \ oplocks.o \ + lease.o \ create.o \ read.o) diff --git a/source4/torture/smb2/persistent_handles.c b/source4/torture/smb2/durable_open.c index 05c5dbbe85..9cc25e3408 100644 --- a/source4/torture/smb2/persistent_handles.c +++ b/source4/torture/smb2/durable_open.c @@ -1,7 +1,7 @@ /* Unix SMB/CIFS implementation. - test suite for SMB2 persistent file handles + test suite for SMB2 durable opens Copyright (C) Stefan Metzmacher 2008 @@ -41,19 +41,19 @@ goto done; \ }} while (0) -/* - basic testing of SMB2 persistent file handles +/* + basic testing of SMB2 durable opens regarding the position information on the handle */ -bool torture_smb2_persistent_handles1(struct torture_context *tctx, - struct smb2_tree *tree1, - struct smb2_tree *tree2) +bool test_durable_open_file_position(struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) { TALLOC_CTX *mem_ctx = talloc_new(tctx); struct smb2_handle h1, h2; struct smb2_create io1, io2; NTSTATUS status; - const char *fname = "persistent_handles.dat"; + const char *fname = "durable_open_position.dat"; DATA_BLOB b; union smb_fileinfo qfinfo; union smb_setfileinfo sfinfo; @@ -181,3 +181,122 @@ bool torture_smb2_persistent_handles1(struct torture_context *tctx, done: return ret; } + +/* + Open, disconnect, oplock break, reconnect. +*/ +bool test_durable_open_oplock(struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_create io1, io2; + struct smb2_handle h1; + NTSTATUS status; + const char *fname = "durable_open_oplock.dat"; + DATA_BLOB b; + bool ret = true; + + /* Clean slate */ + smb2_util_unlink(tree1, fname); + + /* Create with batch oplock */ + ZERO_STRUCT(io1); + io1.in.security_flags = 0x00; + io1.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH; + io1.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + io1.in.create_flags = 0x00000000; + io1.in.reserved = 0x00000000; + io1.in.desired_access = SEC_RIGHTS_FILE_ALL; + io1.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io1.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | + NTCREATEX_SHARE_ACCESS_DELETE; + io1.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + io1.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | + NTCREATEX_OPTIONS_ASYNC_ALERT | + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | + 0x00200000; + io1.in.fname = fname; + + io2 = io1; + io2.in.create_disposition = NTCREATEX_DISP_OPEN; + + b = data_blob_talloc(mem_ctx, NULL, 16); + SBVAL(b.data, 0, 0); + SBVAL(b.data, 8, 0); + + status = smb2_create_blob_add(tree1, &io1.in.blobs, + SMB2_CREATE_TAG_DHNQ, + b); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_create(tree1, mem_ctx, &io1); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH); + CHECK_VAL(io1.out.create_action, NTCREATEX_ACTION_CREATED); + CHECK_VAL(io1.out.alloc_size, 0); + CHECK_VAL(io1.out.size, 0); + CHECK_VAL(io1.out.file_attr, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io1.out.reserved2, 0); + + h1 = io1.out.file.handle; + + /* Disconnect after getting the batch */ + talloc_free(tree1); + tree1 = NULL; + + /* + * Windows7 (build 7000) will break a batch oplock immediately if the + * original client is gone. (ZML: This seems like a bug. It should give + * some time for the client to reconnect!) + */ + status = smb2_create(tree2, mem_ctx, &io2); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH); + CHECK_VAL(io2.out.create_action, NTCREATEX_ACTION_EXISTED); + CHECK_VAL(io2.out.alloc_size, 0); + CHECK_VAL(io2.out.size, 0); + CHECK_VAL(io2.out.file_attr, FILE_ATTRIBUTE_ARCHIVE); + CHECK_VAL(io2.out.reserved2, 0); + + /* What if tree1 tries to come back and reclaim? */ + if (!torture_smb2_connection(tctx, &tree1)) { + torture_warning(tctx, "couldn't reconnect, bailing\n"); + ret = false; + goto done; + } + + ZERO_STRUCT(io2); + io2.in.fname = fname; + + b = data_blob_talloc(tctx, NULL, 16); + SBVAL(b.data, 0, h1.data[0]); + SBVAL(b.data, 8, h1.data[1]); + + status = smb2_create_blob_add(tree2, &io2.in.blobs, + SMB2_CREATE_TAG_DHNC, + b); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_create(tree2, mem_ctx, &io2); + CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); + +done: + return ret; + +} + +struct torture_suite *torture_smb2_durable_open_init(void) +{ + struct torture_suite *suite = + torture_suite_create(talloc_autofree_context(), "DURABLE-OPEN"); + + torture_suite_add_2smb2_test(suite, "FILE-POSITION", + test_durable_open_file_position); + torture_suite_add_2smb2_test(suite, "OPLOCK", test_durable_open_oplock); + + suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests"); + + return suite; +} diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c new file mode 100644 index 0000000000..e67517324b --- /dev/null +++ b/source4/torture/smb2/lease.c @@ -0,0 +1,296 @@ +/* + Unix SMB/CIFS implementation. + + test suite for SMB2 leases + + Copyright (C) Zachary Loafman 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 "includes.h" +#include "librpc/gen_ndr/security.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "torture/torture.h" +#include "torture/smb2/proto.h" + +#define CHECK_VAL(v, correct) do { \ + if ((v) != (correct)) { \ + torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \ + __location__, #v, (int)v, (int)correct); \ + ret = false; \ + }} while (0) + +#define CHECK_STATUS(status, correct) do { \ + if (!NT_STATUS_EQUAL(status, correct)) { \ + torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \ + nt_errstr(status), nt_errstr(correct)); \ + ret = false; \ + goto done; \ + }} while (0) + +static void smb2_lease_create(struct smb2_create *io, struct smb2_lease *ls, + bool dir, const char *name, uint64_t leasekey, + uint32_t leasestate) +{ + ZERO_STRUCT(*io); + io->in.security_flags = 0x00; + io->in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE; + io->in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + io->in.create_flags = 0x00000000; + io->in.reserved = 0x00000000; + io->in.desired_access = SEC_RIGHTS_FILE_ALL; + io->in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io->in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | + NTCREATEX_SHARE_ACCESS_DELETE; + io->in.create_disposition = NTCREATEX_DISP_OPEN_IF; + io->in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | + NTCREATEX_OPTIONS_ASYNC_ALERT | + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | + 0x00200000; + io->in.fname = name; + + if (dir) { + io->in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io->in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE; + io->in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io->in.create_disposition = NTCREATEX_DISP_CREATE; + } + + ZERO_STRUCT(*ls); + ls->lease_key[0] = leasekey; + ls->lease_key[1] = ~leasekey; + ls->lease_state = leasestate; + io->in.lease_request = ls; +} + +#define CHECK_CREATED(__io, __created, __attribute) \ + do { \ + if (__created) { \ + CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_CREATED); \ + } else { \ + CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_EXISTED); \ + } \ + CHECK_VAL((__io)->out.alloc_size, 0); \ + CHECK_VAL((__io)->out.size, 0); \ + CHECK_VAL((__io)->out.file_attr, (__attribute)); \ + CHECK_VAL((__io)->out.reserved2, 0); \ + } while(0) + +#define CHECK_LEASE(__io, __state, __oplevel, __key) \ + do { \ + if (__oplevel) { \ + CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \ + CHECK_VAL((__io)->out.lease_response.lease_key[0], (__key)); \ + CHECK_VAL((__io)->out.lease_response.lease_key[1], ~(__key)); \ + CHECK_VAL((__io)->out.lease_response.lease_state, (__state)); \ + } else { \ + CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \ + CHECK_VAL((__io)->out.lease_response.lease_key[0], 0); \ + CHECK_VAL((__io)->out.lease_response.lease_key[1], 0); \ + CHECK_VAL((__io)->out.lease_response.lease_state, 0); \ + } \ + \ + CHECK_VAL((__io)->out.lease_response.lease_flags, 0); \ + CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \ + } while(0) \ + +static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull; +static const uint64_t LEASE2 = 0xDEADBEEFFEEDBEADull; +static const uint64_t LEASE3 = 0xDAD0FFEDD00DF00Dull; + +#define NRESULTS 8 +static const int request_results[NRESULTS][2] = { + { SMB2_LEASE_NONE, SMB2_LEASE_NONE }, + { SMB2_LEASE_READ, SMB2_LEASE_READ }, + { SMB2_LEASE_HANDLE, SMB2_LEASE_NONE, }, + { SMB2_LEASE_WRITE, SMB2_LEASE_NONE }, + { SMB2_LEASE_READ|SMB2_LEASE_HANDLE, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE }, + { SMB2_LEASE_READ|SMB2_LEASE_WRITE, + SMB2_LEASE_READ|SMB2_LEASE_WRITE }, + { SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE, SMB2_LEASE_NONE }, + { SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE }, +}; + +static bool test_lease_request(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_create io; + struct smb2_lease ls; + struct smb2_handle h1, h2; + NTSTATUS status; + const char *fname = "lease.dat"; + const char *fname2 = "lease2.dat"; + const char *sname = "lease.dat:stream"; + const char *dname = "lease.dir"; + bool ret = true; + int i; + + smb2_util_unlink(tree, fname); + smb2_util_unlink(tree, fname2); + smb2_util_rmdir(tree, dname); + + /* Win7 is happy to grant RHW leases on files. */ + smb2_lease_create(&io, &ls, false, fname, LEASE1, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE); + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + h1 = io.out.file.handle; + CHECK_CREATED(&io, true, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE, + true, LEASE1); + + /* But will reject leases on directories. */ + smb2_lease_create(&io, &ls, true, dname, LEASE2, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE); + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, true, FILE_ATTRIBUTE_DIRECTORY); + CHECK_LEASE(&io, SMB2_LEASE_NONE, false, 0); + smb2_util_close(tree, io.out.file.handle); + + /* Also rejects multiple files leased under the same key. */ + smb2_lease_create(&io, &ls, true, fname2, LEASE1, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE); + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); + + /* And grants leases on streams (with separate leasekey). */ + smb2_lease_create(&io, &ls, false, sname, LEASE2, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE); + status = smb2_create(tree, mem_ctx, &io); + h2 = io.out.file.handle; + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, true, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE, + true, LEASE2); + smb2_util_close(tree, h2); + + smb2_util_close(tree, h1); + + /* Now see what combos are actually granted. */ + for (i = 0; i < NRESULTS; i++) { + torture_comment(tctx, "Testing lease type %x, expecting %x\n", + request_results[i][0], request_results[i][1]); + smb2_lease_create(&io, &ls, false, fname, LEASE1, + request_results[i][0]); + status = smb2_create(tree, mem_ctx, &io); + h2 = io.out.file.handle; + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, false, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, request_results[i][1], true, LEASE1); + smb2_util_close(tree, io.out.file.handle); + } + + done: + smb2_util_close(tree, h1); + smb2_util_close(tree, h2); + + smb2_util_unlink(tree, fname); + smb2_util_unlink(tree, fname2); + smb2_util_rmdir(tree, dname); + + talloc_free(mem_ctx); + + return ret; +} + +static bool test_lease_upgrade(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_create io; + struct smb2_lease ls; + struct smb2_handle h, hnew; + NTSTATUS status; + const char *fname = "lease.dat"; + bool ret = true; + + smb2_util_unlink(tree, fname); + + /* Grab a RH lease. */ + smb2_lease_create(&io, &ls, false, fname, LEASE1, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE); + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, true, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE, true, LEASE1); + h = io.out.file.handle; + + /* Upgrades (sidegrades?) to RW leave us with an RH. */ + smb2_lease_create(&io, &ls, false, fname, LEASE1, + SMB2_LEASE_READ|SMB2_LEASE_WRITE); + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, false, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE, true, LEASE1); + hnew = io.out.file.handle; + + smb2_util_close(tree, hnew); + + /* Upgrade to RHW lease. */ + smb2_lease_create(&io, &ls, false, fname, LEASE1, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE); + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, false, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE, + true, LEASE1); + hnew = io.out.file.handle; + + smb2_util_close(tree, h); + h = hnew; + + /* Attempt to downgrade - original lease state is maintained. */ + smb2_lease_create(&io, &ls, false, fname, LEASE1, + SMB2_LEASE_READ|SMB2_LEASE_HANDLE); + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_CREATED(&io, false, FILE_ATTRIBUTE_ARCHIVE); + CHECK_LEASE(&io, SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE, + true, LEASE1); + hnew = io.out.file.handle; + + smb2_util_close(tree, hnew); + + done: + smb2_util_close(tree, h); + smb2_util_close(tree, hnew); + + smb2_util_unlink(tree, fname); + + talloc_free(mem_ctx); + + return ret; +} + +struct torture_suite *torture_smb2_lease_init(void) +{ + struct torture_suite *suite = + torture_suite_create(talloc_autofree_context(), "LEASE"); + + torture_suite_add_1smb2_test(suite, "REQUEST", test_lease_request); + torture_suite_add_1smb2_test(suite, "UPGRADE", test_lease_upgrade); + + suite->description = talloc_strdup(suite, "SMB2-LEASE tests"); + + return suite; +} diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c index 9418650de4..64456aaed5 100644 --- a/source4/torture/smb2/smb2.c +++ b/source4/torture/smb2/smb2.c @@ -100,11 +100,11 @@ static bool wrap_simple_2smb2_test(struct torture_context *torture_ctx, } -_PUBLIC_ struct torture_test *torture_suite_add_2smb2_test(struct torture_suite *suite, - const char *name, - bool (*run)(struct torture_context *, - struct smb2_tree *, - struct smb2_tree *)) +struct torture_test *torture_suite_add_2smb2_test(struct torture_suite *suite, + const char *name, + bool (*run)(struct torture_context *, + struct smb2_tree *, + struct smb2_tree *)) { struct torture_test *test; struct torture_tcase *tcase; @@ -139,8 +139,9 @@ NTSTATUS torture_smb2_init(void) torture_suite_add_suite(suite, torture_smb2_read_init()); torture_suite_add_suite(suite, torture_smb2_create_init()); torture_suite_add_simple_test(suite, "NOTIFY", torture_smb2_notify); - torture_suite_add_2smb2_test(suite, "PERSISTENT-HANDLES1", torture_smb2_persistent_handles1); + torture_suite_add_suite(suite, torture_smb2_durable_open_init()); torture_suite_add_1smb2_test(suite, "OPLOCK-BATCH1", torture_smb2_oplock_batch1); + torture_suite_add_suite(suite, torture_smb2_lease_init()); suite->description = talloc_strdup(suite, "SMB2-specific tests"); |