diff options
Diffstat (limited to 'source4/utils')
24 files changed, 4781 insertions, 0 deletions
diff --git a/source4/utils/ad2oLschema.c b/source4/utils/ad2oLschema.c new file mode 100644 index 0000000000..e229bd104b --- /dev/null +++ b/source4/utils/ad2oLschema.c @@ -0,0 +1,435 @@ +/* + ldb database library + + Copyright (C) Andrew Bartlett 2006-2008 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: ad2oLschema + * + * Description: utility to convert an AD schema into the format required by OpenLDAP + * + * Author: Andrew Bartlett + */ + +#include "includes.h" +#include "ldb_includes.h" +#include "system/locale.h" +#include "lib/ldb/tools/cmdline.h" +#include "param/param.h" +#include "lib/cmdline/popt_common.h" +#include "dsdb/samdb/samdb.h" + +struct schema_conv { + int count; + int skipped; + int failures; +}; + + +static void usage(void) +{ + printf("Usage: ad2oLschema <options>\n"); + printf("\nConvert AD-like LDIF to OpenLDAP schema format\n\n"); + printf("Options:\n"); + printf(" -I inputfile inputfile of mapped OIDs and skipped attributes/ObjectClasses"); + printf(" -H url LDB or LDAP server to read schmea from\n"); + printf(" -O outputfile outputfile otherwise STDOUT\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Converts records from an AD-like LDIF schema into an openLdap formatted schema\n\n"); + exit(1); +} + +static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) +{ + const char *rootdse_attrs[] = {"schemaNamingContext", NULL}; + struct ldb_dn *schemadn; + struct ldb_dn *basedn = ldb_dn_new(mem_ctx, ldb, NULL); + struct ldb_result *rootdse_res; + struct ldb_result *schema_res; + int ldb_ret; + + if (!basedn) { + return NULL; + } + + /* Search for rootdse */ + ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, rootdse_attrs, &rootdse_res); + if (ldb_ret != LDB_SUCCESS) { + ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, + "(&(objectClass=dMD)(cn=Schema))", + NULL, &schema_res); + if (ldb_ret) { + printf("cn=Schema Search failed: %s\n", ldb_errstring(ldb)); + return NULL; + } + + talloc_steal(mem_ctx, schema_res); + + if (schema_res->count != 1) { + talloc_free(schema_res); + printf("Failed to find rootDSE"); + return NULL; + } + + schemadn = talloc_steal(mem_ctx, schema_res->msgs[0]->dn); + talloc_free(schema_res); + return schemadn; + } + + if (rootdse_res->count != 1) { + printf("Failed to find rootDSE"); + talloc_free(rootdse_res); + return NULL; + } + + /* Locate schema */ + schemadn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, rootdse_res->msgs[0], "schemaNamingContext"); + talloc_free(rootdse_res); + + if (!schemadn) { + return NULL; + } + + return schemadn; +} + + +static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_schema_convert_target target, FILE *in, FILE *out) +{ + /* Read list of attributes to skip, OIDs to map */ + TALLOC_CTX *mem_ctx = talloc_new(ldb); + char *line; + const char **attrs_skip = NULL; + int num_skip = 0; + struct oid_map { + char *old_oid; + char *new_oid; + } *oid_map = NULL; + int num_oid_maps = 0; + struct attr_map { + char *old_attr; + char *new_attr; + } *attr_map = NULL; + int num_attr_maps = 0; + struct dsdb_class *objectclass; + struct dsdb_attribute *attribute; + struct ldb_dn *schemadn; + struct schema_conv ret; + struct dsdb_schema *schema; + const char *seperator; + char *error_string; + + int ldb_ret; + + ret.count = 0; + ret.skipped = 0; + ret.failures = 0; + + while ((line = afdgets(fileno(in), mem_ctx, 0))) { + /* Blank Line */ + if (line[0] == '\0') { + continue; + } + /* Comment */ + if (line[0] == '#') { + continue; + } + if (isdigit(line[0])) { + char *p = strchr(line, ':'); + if (!p) { + ret.failures++; + return ret; + } + p[0] = '\0'; + p++; + oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2); + trim_string(line, " ", " "); + oid_map[num_oid_maps].old_oid = talloc_move(oid_map, &line); + trim_string(p, " ", " "); + oid_map[num_oid_maps].new_oid = p; + num_oid_maps++; + oid_map[num_oid_maps].old_oid = NULL; + } else { + char *p = strchr(line, ':'); + if (p) { + /* remap attribute/objectClass */ + p[0] = '\0'; + p++; + attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2); + trim_string(line, " ", " "); + attr_map[num_attr_maps].old_attr = talloc_move(attr_map, &line); + trim_string(p, " ", " "); + attr_map[num_attr_maps].new_attr = p; + num_attr_maps++; + attr_map[num_attr_maps].old_attr = NULL; + } else { + /* skip attribute/objectClass */ + attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2); + trim_string(line, " ", " "); + attrs_skip[num_skip] = talloc_move(attrs_skip, &line); + num_skip++; + attrs_skip[num_skip] = NULL; + } + } + } + + schemadn = find_schema_dn(ldb, mem_ctx); + if (!schemadn) { + printf("Failed to find schema DN: %s\n", ldb_errstring(ldb)); + ret.failures = 1; + return ret; + } + + ldb_ret = dsdb_schema_from_schema_dn(mem_ctx, ldb, + lp_iconv_convenience(cmdline_lp_ctx), + schemadn, &schema, &error_string); + if (ldb_ret != LDB_SUCCESS) { + printf("Failed to load schema: %s\n", error_string); + ret.failures = 1; + return ret; + } + + switch (target) { + case TARGET_OPENLDAP: + seperator = "\n "; + break; + case TARGET_FEDORA_DS: + seperator = "\n "; + fprintf(out, "dn: cn=schema\n"); + break; + } + + for (attribute=schema->attributes; attribute; attribute = attribute->next) { + const char *name = attribute->lDAPDisplayName; + const char *description = attribute->adminDescription; + const char *oid = attribute->attributeID_oid; + const char *syntax = attribute->attributeSyntax_oid; + const char *equality = NULL, *substring = NULL; + bool single_value = attribute->isSingleValued; + + const struct dsdb_syntax *map = find_syntax_map_by_ad_syntax(attribute->oMSyntax); + char *schema_entry = NULL; + int j; + + /* We have been asked to skip some attributes/objectClasses */ + if (attrs_skip && str_list_check_ci(attrs_skip, name)) { + ret.skipped++; + continue; + } + + /* We might have been asked to remap this oid, due to a conflict */ + for (j=0; oid && oid_map && oid_map[j].old_oid; j++) { + if (strcasecmp(oid, oid_map[j].old_oid) == 0) { + oid = oid_map[j].new_oid; + break; + } + } + + if (map) { + /* We might have been asked to remap this oid, + * due to a conflict, or lack of + * implementation */ + syntax = map->ldap_oid; + /* We might have been asked to remap this oid, due to a conflict */ + for (j=0; syntax && oid_map && oid_map[j].old_oid; j++) { + if (strcasecmp(syntax, oid_map[j].old_oid) == 0) { + syntax = oid_map[j].new_oid; + break; + } + } + + equality = map->equality; + substring = map->substring; + } + + /* We might have been asked to remap this name, due to a conflict */ + for (j=0; name && attr_map && attr_map[j].old_attr; j++) { + if (strcasecmp(name, attr_map[j].old_attr) == 0) { + name = attr_map[j].new_attr; + break; + } + } + + schema_entry = schema_attribute_description(mem_ctx, target, seperator, oid, name, description, equality, substring, syntax, single_value, false); + + if (schema_entry == NULL) { + ret.failures++; + return ret; + } + + switch (target) { + case TARGET_OPENLDAP: + fprintf(out, "attributetype %s\n\n", schema_entry); + break; + case TARGET_FEDORA_DS: + fprintf(out, "attributeTypes: %s\n", schema_entry); + break; + } + ret.count++; + } + + /* This is already sorted to have 'top' and similar classes first */ + for (objectclass=schema->classes; objectclass; objectclass = objectclass->next) { + const char *name = objectclass->lDAPDisplayName; + const char *description = objectclass->adminDescription; + const char *oid = objectclass->governsID_oid; + const char *subClassOf = objectclass->subClassOf; + int objectClassCategory = objectclass->objectClassCategory; + char **must; + char **may; + char *schema_entry = NULL; + const char *objectclass_name_as_list[] = { + objectclass->lDAPDisplayName, + NULL + }; + int j; + int attr_idx; + + /* We have been asked to skip some attributes/objectClasses */ + if (attrs_skip && str_list_check_ci(attrs_skip, name)) { + ret.skipped++; + continue; + } + + /* We might have been asked to remap this oid, due to a conflict */ + for (j=0; oid_map && oid_map[j].old_oid; j++) { + if (strcasecmp(oid, oid_map[j].old_oid) == 0) { + oid = oid_map[j].new_oid; + break; + } + } + + /* We might have been asked to remap this name, due to a conflict */ + for (j=0; name && attr_map && attr_map[j].old_attr; j++) { + if (strcasecmp(name, attr_map[j].old_attr) == 0) { + name = attr_map[j].new_attr; + break; + } + } + + may = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MAY); + + for (j=0; may && may[j]; j++) { + /* We might have been asked to remap this name, due to a conflict */ + for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) { + if (strcasecmp(may[j], attr_map[attr_idx].old_attr) == 0) { + may[j] = attr_map[attr_idx].new_attr; + break; + } + } + } + + must = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MUST); + + for (j=0; must && must[j]; j++) { + /* We might have been asked to remap this name, due to a conflict */ + for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) { + if (strcasecmp(must[j], attr_map[attr_idx].old_attr) == 0) { + must[j] = attr_map[attr_idx].new_attr; + break; + } + } + } + + schema_entry = schema_class_description(mem_ctx, target, + seperator, + oid, + name, + NULL, + description, + subClassOf, + objectClassCategory, + must, + may); + if (schema_entry == NULL) { + ret.failures++; + return ret; + } + + switch (target) { + case TARGET_OPENLDAP: + fprintf(out, "objectclass %s\n\n", schema_entry); + break; + case TARGET_FEDORA_DS: + fprintf(out, "objectClasses: %s\n", schema_entry); + break; + } + ret.count++; + } + + return ret; +} + + int main(int argc, const char **argv) +{ + TALLOC_CTX *ctx; + struct ldb_cmdline *options; + FILE *in = stdin; + FILE *out = stdout; + struct ldb_context *ldb; + struct schema_conv ret; + const char *target_str; + enum dsdb_schema_convert_target target; + + ctx = talloc_new(NULL); + ldb = ldb_init(ctx, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->input) { + in = fopen(options->input, "r"); + if (!in) { + perror(options->input); + exit(1); + } + } + if (options->output) { + out = fopen(options->output, "w"); + if (!out) { + perror(options->output); + exit(1); + } + } + + target_str = lp_parm_string(cmdline_lp_ctx, NULL, "convert", "target"); + + if (!target_str || strcasecmp(target_str, "openldap") == 0) { + target = TARGET_OPENLDAP; + } else if (strcasecmp(target_str, "fedora-ds") == 0) { + target = TARGET_FEDORA_DS; + } else { + printf("Unsupported target: %s\n", target_str); + exit(1); + } + + ret = process_convert(ldb, target, in, out); + + fclose(in); + fclose(out); + + printf("Converted %d records (skipped %d) with %d failures\n", ret.count, ret.skipped, ret.failures); + + return 0; +} diff --git a/source4/utils/config.mk b/source4/utils/config.mk new file mode 100644 index 0000000000..37a19077f1 --- /dev/null +++ b/source4/utils/config.mk @@ -0,0 +1,124 @@ +# utils subsystem + +################################# +# Start BINARY ntlm_auth +[BINARY::ntlm_auth] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG \ + LIBSAMBA-UTIL \ + LIBPOPT \ + POPT_SAMBA \ + POPT_CREDENTIALS \ + gensec \ + LIBCLI_RESOLVE \ + auth \ + ntlm_check \ + MESSAGING \ + LIBEVENTS +# End BINARY ntlm_auth +################################# + +ntlm_auth_OBJ_FILES = $(utilssrcdir)/ntlm_auth.o + +MANPAGES += $(utilssrcdir)/man/ntlm_auth.1 + +################################# +# Start BINARY getntacl +[BINARY::getntacl] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG \ + LIBSAMBA-UTIL \ + NDR_XATTR \ + WRAP_XATTR \ + LIBSAMBA-ERRORS + +getntacl_OBJ_FILES = $(utilssrcdir)/getntacl.o + +# End BINARY getntacl +################################# + +MANPAGES += $(utilssrcdir)/man/getntacl.1 + +################################# +# Start BINARY setntacl +[BINARY::setntacl] +# disabled until rewritten +#INSTALLDIR = BINDIR +# End BINARY setntacl +################################# + +setntacl_OBJ_FILES = $(utilssrcdir)/setntacl.o + +################################# +# Start BINARY setnttoken +[BINARY::setnttoken] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = +# End BINARY setnttoken +################################# + +setnttoken_OBJ_FILES = $(utilssrcdir)/setnttoken.o + +################################# +# Start BINARY nmblookup +[BINARY::nmblookup] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG \ + LIBSAMBA-UTIL \ + LIBCLI_NBT \ + LIBPOPT \ + POPT_SAMBA \ + LIBNETIF \ + LIBCLI_RESOLVE +# End BINARY nmblookup +################################# + +nmblookup_OBJ_FILES = $(utilssrcdir)/nmblookup.o + +################################# +# Start BINARY testparm +[BINARY::testparm] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG \ + LIBSAMBA-UTIL \ + LIBPOPT \ + samba-socket \ + POPT_SAMBA \ + LIBCLI_RESOLVE \ + CHARSET +# End BINARY testparm +################################# + +testparm_OBJ_FILES = $(utilssrcdir)/testparm.o + +################################################ +# Start BINARY oLschema2ldif +[BINARY::oLschema2ldif] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE SAMDB +# End BINARY oLschema2ldif +################################################ + + +oLschema2ldif_OBJ_FILES = $(addprefix $(utilssrcdir)/, oLschema2ldif.o) + +MANPAGES += $(utilssrcdir)/man/oLschema2ldif.1 + +################################################ +# Start BINARY ad2oLschema +[BINARY::ad2oLschema] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE SAMDB +# End BINARY ad2oLschema +################################################ + +ad2oLschema_OBJ_FILES = $(addprefix $(utilssrcdir)/, ad2oLschema.o) + +MANPAGES += $(utilssrcdir)/man/ad2oLschema.1 + diff --git a/source4/utils/getntacl.c b/source4/utils/getntacl.c new file mode 100644 index 0000000000..132d689dcb --- /dev/null +++ b/source4/utils/getntacl.c @@ -0,0 +1,121 @@ +/* + Unix SMB/CIFS implementation. + + Get NT ACLs from UNIX files. + + Copyright (C) Tim Potter <tpot@samba.org> 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 "includes.h" +#include "system/filesys.h" +#include "librpc/gen_ndr/ndr_xattr.h" +#include "lib/util/wrap_xattr.h" +#include "param/param.h" + +static void ntacl_print_debug_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3); + +static void ntacl_print_debug_helper(struct ndr_print *ndr, const char *format, ...) +{ + va_list ap; + char *s = NULL; + int i; + + va_start(ap, format); + vasprintf(&s, format, ap); + va_end(ap); + + for (i=0;i<ndr->depth;i++) { + printf(" "); + } + + printf("%s\n", s); + free(s); +} + +static NTSTATUS get_ntacl(TALLOC_CTX *mem_ctx, + char *filename, + struct xattr_NTACL **ntacl, + ssize_t *ntacl_len) +{ + DATA_BLOB blob; + ssize_t size; + enum ndr_err_code ndr_err; + struct ndr_pull *ndr; + + *ntacl = talloc(mem_ctx, struct xattr_NTACL); + + size = wrap_getxattr(filename, XATTR_NTACL_NAME, NULL, 0); + + if (size < 0) { + fprintf(stderr, "get_ntacl: %s\n", strerror(errno)); + return NT_STATUS_INTERNAL_ERROR; + } + + blob.data = talloc_array(*ntacl, uint8_t, size); + size = wrap_getxattr(filename, XATTR_NTACL_NAME, blob.data, size); + if (size < 0) { + fprintf(stderr, "get_ntacl: %s\n", strerror(errno)); + return NT_STATUS_INTERNAL_ERROR; + } + blob.length = size; + + ndr = ndr_pull_init_blob(&blob, NULL, NULL); + + ndr_err = ndr_pull_xattr_NTACL(ndr, NDR_SCALARS|NDR_BUFFERS, *ntacl); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + return NT_STATUS_OK; +} + +static void print_ntacl(TALLOC_CTX *mem_ctx, + const char *fname, + struct xattr_NTACL *ntacl) +{ + struct ndr_print *pr; + + pr = talloc_zero(mem_ctx, struct ndr_print); + if (!pr) return; + pr->print = ntacl_print_debug_helper; + + ndr_print_xattr_NTACL(pr, fname, ntacl); + talloc_free(pr); +} + +int main(int argc, char *argv[]) +{ + NTSTATUS status; + struct xattr_NTACL *ntacl; + ssize_t ntacl_len; + + if (argc != 2) { + fprintf(stderr, "Usage: getntacl FILENAME\n"); + return 1; + } + + status = get_ntacl(NULL, argv[1], &ntacl, &ntacl_len); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "get_ntacl failed: %s\n", nt_errstr(status)); + return 1; + } + + print_ntacl(ntacl, argv[1], ntacl); + + talloc_free(ntacl); + + return 0; +} diff --git a/source4/utils/man/ad2oLschema.1.xml b/source4/utils/man/ad2oLschema.1.xml new file mode 100644 index 0000000000..6ae8996477 --- /dev/null +++ b/source4/utils/man/ad2oLschema.1.xml @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> +<refentry id="ad2oLschema.1"> + +<refmeta> + <refentrytitle>ad2oLschema</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>ad2oLschema</refname> + <refpurpose>Converts AC-like LDAP schemas to OpenLDAP + compatible schema files</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>ad2oLschema</command> + <arg choice="opt">-I INPUT-FILE</arg> + <arg choice="opt">-O OUTPUT-FILE</arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>ad2oLschema is a simple tool that converts AD-like LDIF + schema files into OpenLDAP schema files.</para> +</refsect1> + + +<refsect1> + <title>OPTIONS</title> + + <variablelist> + <varlistentry> + <term>-H url</term> + <listitem><para>URL to an LDB or LDAP server with an AD schema to read. </para></listitem> + </varlistentry> + + <varlistentry> + <term>-I input-file</term> <listitem><para>AD schema + to read. If neither this nor -H is specified, the + schema file will be read from standard input. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>-O output-file</term> + <listitem><para>File to write OpenLDAP version of schema to. + </para></listitem> + </varlistentry> + </variablelist> +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 4.0 of the Samba suite.</para> +</refsect1> + +<refsect1> + <title>SEE ALSO</title> + + <para>ldb(7), ldbmodify, ldbdel, ldif(5)</para> + +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para> ldb was written by + <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>. + ad2oLschema was written by <ulink + url="http://samba.org/~abartlet/">Andrew Bartlett</ulink>. + </para> + + <para> +If you wish to report a problem or make a suggestion then please see +the <ulink url="http://ldb.samba.org/"/> web site for +current contact and maintainer information. + </para> + +</refsect1> + +</refentry> diff --git a/source4/utils/man/getntacl.1.xml b/source4/utils/man/getntacl.1.xml new file mode 100644 index 0000000000..cbce5f2103 --- /dev/null +++ b/source4/utils/man/getntacl.1.xml @@ -0,0 +1,45 @@ +<?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="getntacl.1"> + +<refmeta> + <refentrytitle>getntacl</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>getntacl</refname> + <refpurpose>Tool for displaying NT ACLs stored in extended attributes</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>getntacl</command> + <arg choice="req">filename</arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>Retrieves the NT security ACL on the specified file, as +stored in the filesystems' extended attribute. </para> +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 4.0 of the Samba suite.</para> +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para> + + <para>This manpage was written by Jelmer Vernooij. </para> + +</refsect1> + +</refentry> diff --git a/source4/utils/man/ndrdump.1.xml b/source4/utils/man/ndrdump.1.xml new file mode 100644 index 0000000000..9d66102682 --- /dev/null +++ b/source4/utils/man/ndrdump.1.xml @@ -0,0 +1,83 @@ +<?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="ndrdump.1"> + +<refmeta> + <refentrytitle>ndrdump</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>ndrdump</refname> + <refpurpose>DCE/RPC Packet Parser and Dumper</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>ndrdump</command> + <arg choice="opt">-c context</arg> + <arg choice="req">pipe</arg> + <arg choice="req">function</arg> + <arg choice="req">in|out</arg> + <arg choice="req">filename</arg> + </cmdsynopsis> + <cmdsynopsis> + <command>ndrdump</command> + <arg choice="opt">pipe</arg> + </cmdsynopsis> + <cmdsynopsis> + <command>ndrdump</command> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>ndrdump tries to parse the specified <replaceable>filename</replaceable> + using Samba's parser for the specified pipe and function. The + third argument should be + either <emphasis>in</emphasis> or <emphasis>out</emphasis>, depending + on whether the data should be parsed as a request or a reply.</para> + + <para>Running ndrdump without arguments will list the pipes for which + parsers are available.</para> + + <para>Running ndrdump with one argument will list the functions that + Samba can parse for the specified pipe.</para> + + <para>The primary function of ndrdump is debugging Samba's internal + DCE/RPC parsing functions. The file being parsed is usually + one exported by wiresharks <quote>Export selected packet bytes</quote> + function.</para> + + <para>The context argument can be used to load context data from the request + packet when parsing reply packets (such as array lengths).</para> + +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 4.0 of the Samba suite.</para> +</refsect1> + +<refsect1> + <title>SEE ALSO</title> + + <para>wireshark, pidl</para> + +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para> + + <para>ndrdump was written by Andrew Tridgell. </para> + + <para>This manpage was written by Jelmer Vernooij. </para> + +</refsect1> + +</refentry> diff --git a/source4/utils/man/ntlm_auth.1.xml b/source4/utils/man/ntlm_auth.1.xml new file mode 100644 index 0000000000..1677500112 --- /dev/null +++ b/source4/utils/man/ntlm_auth.1.xml @@ -0,0 +1,269 @@ +<?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="ntlm-auth.1"> + +<refmeta> + <refentrytitle>ntlm_auth</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>ntlm_auth</refname> + <refpurpose>tool to allow external access to Winbind's NTLM authentication function</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>ntlm_auth</command> + <arg choice="opt">-d debuglevel</arg> + <arg choice="opt">-l logdir</arg> + <arg choice="opt">-s <smb config file></arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle> + <manvolnum>7</manvolnum></citerefentry> suite.</para> + + <para><command>ntlm_auth</command> is a helper utility that authenticates + users using NT/LM authentication. It returns 0 if the users is authenticated + successfully and 1 if access was denied. ntlm_auth uses winbind to access + the user and authentication data for a domain. This utility + is only indended to be used by other programs (currently squid). + </para> +</refsect1> + +<refsect1> + <title>OPERATIONAL REQUIREMENTS</title> + + <para> + The <citerefentry><refentrytitle>winbindd</refentrytitle> + <manvolnum>8</manvolnum></citerefentry> daemon must be operational + for many of these commands to function.</para> + + <para>Some of these commands also require access to the directory + <filename>winbindd_privileged</filename> in + <filename>$LOCKDIR</filename>. This should be done either by running + this command as root or providing group access + to the <filename>winbindd_privileged</filename> directory. For + security reasons, this directory should not be world-accessable. </para> + +</refsect1> + + +<refsect1> + <title>OPTIONS</title> + + <variablelist> + <varlistentry> + <term>--helper-protocol=PROTO</term> + <listitem><para> + Operate as a stdio-based helper. Valid helper protocols are: + </para> + <variablelist> + <varlistentry> + <term>squid-2.4-basic</term> + <listitem><para> + Server-side helper for use with Squid 2.4's basic (plaintext) + authentication. </para> + </listitem> + </varlistentry> + <varlistentry> + <term>squid-2.5-basic</term> + <listitem><para> + Server-side helper for use with Squid 2.5's basic (plaintext) + authentication. </para> + </listitem> + </varlistentry> + <varlistentry> + <term>squid-2.5-ntlmssp</term> + <listitem><para> + Server-side helper for use with Squid 2.5's NTLMSSP + authentication. </para> + <para>Requires access to the directory + <filename>winbindd_privileged</filename> in + <filename>$LOCKDIR</filename>. The protocol used is + described here: <ulink + url="http://devel.squid-cache.org/ntlm/squid_helper_protocol.html">http://devel.squid-cache.org/ntlm/squid_helper_protocol.html</ulink> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>ntlmssp-client-1</term> + <listitem><para> + Cleint-side helper for use with arbitary external + programs that may wish to use Samba's NTLMSSP + authentication knowlege. </para> + <para>This helper is a client, and as such may be run by any + user. The protocol used is + effectivly the reverse of the previous protocol. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>gss-spnego</term> + <listitem><para> + Server-side helper that implements GSS-SPNEGO. This + uses a protocol that is almost the same as + <command>squid-2.5-ntlmssp</command>, but has some + subtle differences that are undocumented outside the + source at this stage. + </para> + <para>Requires access to the directory + <filename>winbindd_privileged</filename> in + <filename>$LOCKDIR</filename>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>gss-spnego-client</term> + <listitem><para> + Client-side helper that implements GSS-SPNEGO. This + also uses a protocol similar to the above helpers, but + is currently undocumented. + </para> + </listitem> + </varlistentry> + </variablelist> + </listitem> + </varlistentry> + + <varlistentry> + <term>--username=USERNAME</term> + <listitem><para> + Specify username of user to authenticate + </para></listitem> + + </varlistentry> + + <varlistentry> + <term>--domain=DOMAIN</term> + <listitem><para> + Specify domain of user to authenticate + </para></listitem> + </varlistentry> + + <varlistentry> + <term>--workstation=WORKSTATION</term> + <listitem><para> + Specify the workstation the user authenticated from + </para></listitem> + </varlistentry> + + <varlistentry> + <term>--challenge=STRING</term> + <listitem><para>NTLM challenge (in HEXADECIMAL)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>--lm-response=RESPONSE</term> + <listitem><para>LM Response to the challenge (in HEXADECIMAL)</para></listitem> + </varlistentry> + + <varlistentry> + <term>--nt-response=RESPONSE</term> + <listitem><para>NT or NTLMv2 Response to the challenge (in HEXADECIMAL)</para></listitem> + </varlistentry> + + <varlistentry> + <term>--password=PASSWORD</term> + <listitem><para>User's plaintext password</para><para>If + not specified on the command line, this is prompted for when + required. </para></listitem> + </varlistentry> + + <varlistentry> + <term>--request-lm-key</term> + <listitem><para>Retreive LM session key</para></listitem> + </varlistentry> + + <varlistentry> + <term>--request-nt-key</term> + <listitem><para>Request NT key</para></listitem> + </varlistentry> + + <varlistentry> + <term>--diagnostics</term> + <listitem><para>Perform Diagnostics on the authentication + chain. Uses the password from <command>--password</command> + or prompts for one.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>--require-membership-of={SID|Name}</term> + <listitem><para>Require that a user be a member of specified + group (either name or SID) for authentication to succeed.</para> + </listitem> + </varlistentry> + + &popt.common.samba; + &stdarg.help; + + </variablelist> +</refsect1> + +<refsect1> + <title>EXAMPLE SETUP</title> + + <para>To setup ntlm_auth for use by squid 2.5, with both basic and + NTLMSSP authentication, the following + should be placed in the <filename>squid.conf</filename> file. +<programlisting> +auth_param ntlm program ntlm_auth --helper-protocol=squid-2.5-ntlmssp +auth_param basic program ntlm_auth --helper-protocol=squid-2.5-basic +auth_param basic children 5 +auth_param basic realm Squid proxy-caching web server +auth_param basic credentialsttl 2 hours +</programlisting></para> + +<note><para>This example assumes that ntlm_auth has been installed into your + path, and that the group permissions on + <filename>winbindd_privileged</filename> are as described above.</para></note> + + <para>To setup ntlm_auth for use by squid 2.5 with group limitation in addition to the above + example, the following should be added to the <filename>squid.conf</filename> file. +<programlisting> +auth_param ntlm program ntlm_auth --helper-protocol=squid-2.5-ntlmssp --require-membership-of='WORKGROUP\Domain Users' +auth_param basic program ntlm_auth --helper-protocol=squid-2.5-basic --require-membership-of='WORKGROUP\Domain Users' +</programlisting></para> + +</refsect1> + +<refsect1> + <title>TROUBLESHOOTING</title> + + <para>If you're experiencing problems with authenticating Internet Explorer running + under MS Windows 9X or Millenium Edition against ntlm_auth's NTLMSSP authentication + helper (--helper-protocol=squid-2.5-ntlmssp), then please read + <ulink url="http://support.microsoft.com/support/kb/articles/Q239/8/69.ASP"> + the Microsoft Knowledge Base article #239869 and follow instructions described there</ulink>. + </para> +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 3.0 of the Samba + suite.</para> +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para>The original Samba software and related utilities + were created by Andrew Tridgell. Samba is now developed + by the Samba Team as an Open Source project similar + to the way the Linux kernel is developed.</para> + + <para>The ntlm_auth manpage was written by Jelmer Vernooij and + Andrew Bartlett.</para> +</refsect1> + +</refentry> diff --git a/source4/utils/man/oLschema2ldif.1.xml b/source4/utils/man/oLschema2ldif.1.xml new file mode 100644 index 0000000000..b1e681be4e --- /dev/null +++ b/source4/utils/man/oLschema2ldif.1.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> +<refentry id="oLschema2ldif.1"> + +<refmeta> + <refentrytitle>oLschema2ldif</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>oLschema2ldif</refname> + <refpurpose>Converts LDAP schema's to LDB-compatible LDIF</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>oLschema2ldif</command> + <arg choice="opt">-I INPUT-FILE</arg> + <arg choice="opt">-O OUTPUT-FILE</arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>oLschema2ldif is a simple tool that converts standard OpenLDAP schema files to a LDIF format that is understood by LDB.</para> +</refsect1> + + +<refsect1> + <title>OPTIONS</title> + + <variablelist> + <varlistentry> + <term>-I input-file</term> + <listitem><para>OpenLDAP schema to read. If none are specified, +the schema file will be read from standard input. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>-O output-file</term> + <listitem><para>File to write ldif version of schema to. + </para></listitem> + </varlistentry> + </variablelist> +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 4.0 of the Samba suite.</para> +</refsect1> + +<refsect1> + <title>SEE ALSO</title> + + <para>ldb(7), ldbmodify, ldbdel, ldif(5)</para> + +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para> ldb was written by + <ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>. + oLschema2ldif was written by <ulink url="mailto:idra@samba.org">Simo Sorce</ulink>. + </para> + + <para> +If you wish to report a problem or make a suggestion then please see +the <ulink url="http://ldb.samba.org/"/> web site for +current contact and maintainer information. + </para> + +</refsect1> + +</refentry> diff --git a/source4/utils/net/config.mk b/source4/utils/net/config.mk new file mode 100644 index 0000000000..93b51e1e28 --- /dev/null +++ b/source4/utils/net/config.mk @@ -0,0 +1,26 @@ +# $(utilssrcdir)/net subsystem + +################################# +# Start BINARY net +[BINARY::net] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG \ + LIBSAMBA-UTIL \ + LIBSAMBA-NET \ + LIBPOPT \ + POPT_SAMBA \ + POPT_CREDENTIALS +# End BINARY net +################################# + +net_OBJ_FILES = $(addprefix $(utilssrcdir)/net/, \ + net.o \ + net_password.o \ + net_time.o \ + net_join.o \ + net_vampire.o \ + net_user.o) + + +$(eval $(call proto_header_template,$(utilssrcdir)/net/net_proto.h,$(net_OBJ_FILES:.o=.c))) diff --git a/source4/utils/net/net.c b/source4/utils/net/net.c new file mode 100644 index 0000000000..1c834fe4f0 --- /dev/null +++ b/source4/utils/net/net.c @@ -0,0 +1,217 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) 2001 Steve French (sfrench@us.ibm.com) + Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com) + Copyright (C) 2001 Andrew Tridgell (tridge@samba.org) + Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org) + Copyright (C) 2004 Stefan Metzmacher (metze@samba.org) + + Largely rewritten by metze in August 2004 + + Originally written by Steve and Jim. Largely rewritten by tridge in + November 2001. + + Reworked again by abartlet in December 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/>. +*/ + +/*****************************************************/ +/* */ +/* Distributed SMB/CIFS Server Management Utility */ +/* */ +/* The intent was to make the syntax similar */ +/* to the NET utility (first developed in DOS */ +/* with additional interesting & useful functions */ +/* added in later SMB server network operating */ +/* systems). */ +/* */ +/*****************************************************/ + +#include "includes.h" +#include "utils/net/net.h" +#include "lib/cmdline/popt_common.h" +#include "lib/ldb/include/ldb.h" +#include "librpc/rpc/dcerpc.h" +#include "param/param.h" +#include "lib/events/events.h" +#include "auth/credentials/credentials.h" + +/* + run a function from a function table. If not found then + call the specified usage function +*/ +int net_run_function(struct net_context *ctx, + int argc, const char **argv, + const struct net_functable *functable, + int (*usage_fn)(struct net_context *ctx, int argc, const char **argv)) +{ + int i; + + if (argc == 0) { + return usage_fn(ctx, argc, argv); + + } else if (argc == 1 && strequal(argv[0], "help")) { + return net_help(ctx, functable); + } + + for (i=0; functable[i].name; i++) { + if (strcasecmp_m(argv[0], functable[i].name) == 0) + return functable[i].fn(ctx, argc-1, argv+1); + } + + d_printf("No command: %s\n", argv[0]); + return usage_fn(ctx, argc, argv); +} + +/* + run a usage function from a function table. If not found then fail +*/ +int net_run_usage(struct net_context *ctx, + int argc, const char **argv, + const struct net_functable *functable) +{ + int i; + + for (i=0; functable[i].name; i++) { + if (strcasecmp_m(argv[0], functable[i].name) == 0) + if (functable[i].usage) { + return functable[i].usage(ctx, argc-1, argv+1); + } + } + + d_printf("No usage information for command: %s\n", argv[0]); + + return 1; +} + + +/* main function table */ +static const struct net_functable net_functable[] = { + {"password", "change password\n", net_password, net_password_usage}, + {"time", "get remote server's time\n", net_time, net_time_usage}, + {"join", "join a domain\n", net_join, net_join_usage}, + {"samdump", "dump the sam of a domain\n", net_samdump, net_samdump_usage}, + {"vampire", "join and syncronise an AD domain onto the local server\n", net_vampire, net_vampire_usage}, + {"samsync", "synchronise into the local ldb the sam of an NT4 domain\n", net_samsync_ldb, net_samsync_ldb_usage}, + {"user", "manage user accounts\n", net_user, net_user_usage}, + {NULL, NULL, NULL, NULL} +}; + +int net_help(struct net_context *ctx, const struct net_functable *ftable) +{ + int i = 0; + const char *name = ftable[i].name; + const char *desc = ftable[i].desc; + + d_printf("Available commands:\n"); + while (name && desc) { + d_printf("\t%s\t\t%s", name, desc); + name = ftable[++i].name; + desc = ftable[i].desc; + } + + return 0; +} + +static int net_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("Usage:\n"); + d_printf("net <command> [options]\n"); + return 0; +} + +/**************************************************************************** + main program +****************************************************************************/ +static int binary_net(int argc, const char **argv) +{ + int opt,i; + int rc; + int argc_new; + const char **argv_new; + struct event_context *ev; + struct net_context *ctx = NULL; + poptContext pc; + struct poptOption long_options[] = { + POPT_AUTOHELP + POPT_COMMON_SAMBA + POPT_COMMON_CONNECTION + POPT_COMMON_CREDENTIALS + POPT_COMMON_VERSION + { NULL } + }; + + setlinebuf(stdout); + + pc = poptGetContext("net", argc, (const char **) argv, long_options, + POPT_CONTEXT_KEEP_FIRST); + + while((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + default: + d_printf("Invalid option %s: %s\n", + poptBadOption(pc, 0), poptStrerror(opt)); + net_usage(ctx, argc, argv); + exit(1); + } + } + + argv_new = (const char **)poptGetArgs(pc); + + argc_new = argc; + for (i=0; i<argc; i++) { + if (argv_new[i] == NULL) { + argc_new = i; + break; + } + } + + if (argc_new < 2) { + return net_usage(ctx, argc, argv); + } + + dcerpc_init(); + + ev = s4_event_context_init(NULL); + if (!ev) { + d_printf("Failed to create an event context\n"); + exit(1); + } + ctx = talloc(ev, struct net_context); + if (!ctx) { + d_printf("Failed to talloc a net_context\n"); + exit(1); + } + + ZERO_STRUCTP(ctx); + ctx->lp_ctx = cmdline_lp_ctx; + ctx->credentials = cmdline_credentials; + ctx->event_ctx = ev; + + rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable, net_usage); + + if (rc != 0) { + DEBUG(0,("return code = %d\n", rc)); + } + + talloc_free(ev); + return rc; +} + + int main(int argc, const char **argv) +{ + return binary_net(argc, argv); +} diff --git a/source4/utils/net/net.h b/source4/utils/net/net.h new file mode 100644 index 0000000000..309bee277c --- /dev/null +++ b/source4/utils/net/net.h @@ -0,0 +1,39 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + + Copyright (C) Stefan Metzmacher 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/>. +*/ + +#ifndef _UTIL_NET_H +#define _UTIL_NET_H + +struct net_context { + struct cli_credentials *credentials; + struct loadparm_context *lp_ctx; + struct event_context *event_ctx; +}; + +struct net_functable { + const char *name; + const char *desc; + int (*fn)(struct net_context *ctx, int argc, const char **argv); + int (*usage)(struct net_context *ctx, int argc, const char **argv); +}; + +#include "utils/net/net_proto.h" + +#endif /* _UTIL_NET_H */ diff --git a/source4/utils/net/net_join.c b/source4/utils/net/net_join.c new file mode 100644 index 0000000000..ad63340089 --- /dev/null +++ b/source4/utils/net/net_join.c @@ -0,0 +1,170 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + + Copyright (C) 2004 Stefan Metzmacher <metze@samba.org> + Copyright (C) 2005 Andrew Bartlett <abartlet@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 "utils/net/net.h" +#include "libnet/libnet.h" +#include "libcli/security/security.h" +#include "param/param.h" +#include "lib/events/events.h" + +int net_join(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *libnetctx; + struct libnet_Join *r; + char *tmp; + const char *domain_name; + enum netr_SchannelType secure_channel_type = SEC_CHAN_WKSTA; + + switch (argc) { + case 0: /* no args -> fail */ + return net_join_usage(ctx, argc, argv); + case 1: /* only DOMAIN */ + tmp = talloc_strdup(ctx, argv[0]); + break; + case 2: /* DOMAIN and role */ + tmp = talloc_strdup(ctx, argv[0]); + if (strcasecmp(argv[1], "BDC") == 0) { + secure_channel_type = SEC_CHAN_BDC; + } else if (strcasecmp(argv[1], "MEMBER") == 0) { + secure_channel_type = SEC_CHAN_WKSTA; + } else { + d_fprintf(stderr, "net_join: Invalid 2nd argument (%s) must be MEMBER or BDC\n", argv[1]); + return net_join_usage(ctx, argc, argv); + } + break; + default: /* too many args -> fail */ + return net_join_usage(ctx, argc, argv); + } + + domain_name = tmp; + + libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!libnetctx) { + return -1; + } + libnetctx->cred = ctx->credentials; + r = talloc(ctx, struct libnet_Join); + if (!r) { + return -1; + } + /* prepare parameters for the join */ + r->in.netbios_name = lp_netbios_name(ctx->lp_ctx); + r->in.domain_name = domain_name; + r->in.join_type = secure_channel_type; + r->in.level = LIBNET_JOIN_AUTOMATIC; + r->out.error_string = NULL; + + /* do the domain join */ + status = libnet_Join(libnetctx, r, r); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Joining domain failed: %s\n", + r->out.error_string ? r->out.error_string : nt_errstr(status)); + talloc_free(r); + talloc_free(libnetctx); + return -1; + } + d_printf("Joined domain %s (%s)\n", r->out.domain_name, dom_sid_string(ctx, r->out.domain_sid)); + + talloc_free(libnetctx); + return 0; +} + +int net_join_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net join <domain> [BDC | MEMBER] [options]\n"); + return 0; +} + +int net_join_help(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("Joins domain as either member or backup domain controller.\n"); + return 0; +} + +int net_vampire(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *libnetctx; + struct libnet_Vampire *r; + char *tmp, *targetdir = NULL; + const char *domain_name; + + switch (argc) { + case 0: /* no args -> fail */ + return net_vampire_usage(ctx, argc, argv); + case 1: /* only DOMAIN */ + tmp = talloc_strdup(ctx, argv[0]); + break; + case 2: /* domain and target dir */ + tmp = talloc_strdup(ctx, argv[0]); + targetdir = talloc_strdup(ctx, argv[1]); + break; + default: /* too many args -> fail */ + return net_vampire_usage(ctx, argc, argv); + } + + domain_name = tmp; + + libnetctx = libnet_context_init(NULL, ctx->lp_ctx); + if (!libnetctx) { + return -1; + } + libnetctx->cred = ctx->credentials; + r = talloc(ctx, struct libnet_Vampire); + if (!r) { + return -1; + } + /* prepare parameters for the vampire */ + r->in.netbios_name = lp_netbios_name(ctx->lp_ctx); + r->in.domain_name = domain_name; + r->in.targetdir = targetdir; + r->out.error_string = NULL; + + /* do the domain vampire */ + status = libnet_Vampire(libnetctx, r, r); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Vampire of domain failed: %s\n", + r->out.error_string ? r->out.error_string : nt_errstr(status)); + talloc_free(r); + talloc_free(libnetctx); + return -1; + } + d_printf("Vampired domain %s (%s)\n", r->out.domain_name, dom_sid_string(ctx, r->out.domain_sid)); + + talloc_free(libnetctx); + return 0; +} + +int net_vampire_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net vampire <domain> [options]\n"); + return 0; +} + +int net_vampire_help(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("Vampires domain as either member or backup domain controller.\n"); + return 0; +} diff --git a/source4/utils/net/net_password.c b/source4/utils/net/net_password.c new file mode 100644 index 0000000000..55f7c3c31d --- /dev/null +++ b/source4/utils/net/net_password.c @@ -0,0 +1,171 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + + Copyright (C) 2004 Stefan Metzmacher (metze@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 "utils/net/net.h" +#include "libnet/libnet.h" +#include "system/filesys.h" +#include "lib/events/events.h" +#include "auth/credentials/credentials.h" + +/* + * Code for Changing and setting a password + */ + +static int net_password_change_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net_password_change_usage: TODO\n"); + return 0; +} + + +static int net_password_change(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *libnetctx; + union libnet_ChangePassword r; + char *password_prompt = NULL; + const char *new_password; + + if (argc > 0 && argv[0]) { + new_password = argv[0]; + } else { + password_prompt = talloc_asprintf(ctx, "Enter new password for account [%s\\%s]:", + cli_credentials_get_domain(ctx->credentials), + cli_credentials_get_username(ctx->credentials)); + new_password = getpass(password_prompt); + } + + libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!libnetctx) { + return -1; + } + libnetctx->cred = ctx->credentials; + + /* prepare password change */ + r.generic.level = LIBNET_CHANGE_PASSWORD_GENERIC; + r.generic.in.account_name = cli_credentials_get_username(ctx->credentials); + r.generic.in.domain_name = cli_credentials_get_domain(ctx->credentials); + r.generic.in.oldpassword = cli_credentials_get_password(ctx->credentials); + r.generic.in.newpassword = new_password; + + /* do password change */ + status = libnet_ChangePassword(libnetctx, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("net_password_change: %s\n",r.generic.out.error_string)); + return -1; + } + + talloc_free(libnetctx); + + return 0; +} + + +static int net_password_set_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net_password_set_usage: TODO\n"); + return 0; +} + + +static int net_password_set(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *libnetctx; + union libnet_SetPassword r; + char *password_prompt = NULL; + char *p; + char *tmp; + const char *account_name; + const char *domain_name; + const char *new_password = NULL; + + switch (argc) { + case 0: /* no args -> fail */ + return net_password_set_usage(ctx, argc, argv); + case 1: /* only DOM\\user; prompt for password */ + tmp = talloc_strdup(ctx, argv[0]); + break; + case 2: /* DOM\\USER and password */ + tmp = talloc_strdup(ctx, argv[0]); + new_password = argv[1]; + break; + default: /* too mayn args -> fail */ + DEBUG(0,("net_password_set: too many args [%d]\n",argc)); + return net_password_usage(ctx, argc, argv); + } + + if ((p = strchr_m(tmp,'\\'))) { + *p = 0; + domain_name = tmp; + account_name = talloc_strdup(ctx, p+1); + } else { + account_name = tmp; + domain_name = cli_credentials_get_domain(ctx->credentials); + } + + if (!new_password) { + password_prompt = talloc_asprintf(ctx, "Enter new password for account [%s\\%s]:", + domain_name, account_name); + new_password = getpass(password_prompt); + } + + libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!libnetctx) { + return -1; + } + libnetctx->cred = ctx->credentials; + + /* prepare password change */ + r.generic.level = LIBNET_SET_PASSWORD_GENERIC; + r.generic.in.account_name = account_name; + r.generic.in.domain_name = domain_name; + r.generic.in.newpassword = new_password; + + /* do password change */ + status = libnet_SetPassword(libnetctx, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("net_password_set: %s\n",r.generic.out.error_string)); + return -1; + } + + talloc_free(libnetctx); + + return 0; +} + + +static const struct net_functable net_password_functable[] = { + {"change", "change password (old password required)\n", net_password_change, net_password_change_usage }, + {"set", "set password\n", net_password_set, net_password_set_usage }, + {NULL, NULL} +}; + +int net_password(struct net_context *ctx, int argc, const char **argv) +{ + return net_run_function(ctx, argc, argv, net_password_functable, net_password_usage); +} + +int net_password_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net password <command> [options]\n"); + return 0; +} diff --git a/source4/utils/net/net_time.c b/source4/utils/net/net_time.c new file mode 100644 index 0000000000..92e6e77481 --- /dev/null +++ b/source4/utils/net/net_time.c @@ -0,0 +1,78 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + + Copyright (C) 2004 Stefan Metzmacher (metze@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 "libnet/libnet.h" +#include "utils/net/net.h" +#include "system/time.h" +#include "lib/events/events.h" + +/* + * Code for getting the remote time + */ + +int net_time(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *libnetctx; + union libnet_RemoteTOD r; + const char *server_name; + struct tm *tm; + char timestr[64]; + + if (argc > 0 && argv[0]) { + server_name = argv[0]; + } else { + return net_time_usage(ctx, argc, argv); + } + + libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!libnetctx) { + return -1; + } + libnetctx->cred = ctx->credentials; + + /* prepare to get the time */ + r.generic.level = LIBNET_REMOTE_TOD_GENERIC; + r.generic.in.server_name = server_name; + + /* get the time */ + status = libnet_RemoteTOD(libnetctx, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("net_time: %s\n",r.generic.out.error_string)); + return -1; + } + + ZERO_STRUCT(timestr); + tm = localtime(&r.generic.out.time); + strftime(timestr, sizeof(timestr)-1, "%c %Z",tm); + + printf("%s\n",timestr); + + talloc_free(libnetctx); + + return 0; +} + +int net_time_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net time <server> [options]\n"); + return 0; +} diff --git a/source4/utils/net/net_user.c b/source4/utils/net/net_user.c new file mode 100644 index 0000000000..c4b8ecb0c2 --- /dev/null +++ b/source4/utils/net/net_user.c @@ -0,0 +1,125 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + + Copyright (C) Rafal Szczesniak <mimir@samba.org> 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 "includes.h" +#include "utils/net/net.h" +#include "libnet/libnet.h" +#include "lib/events/events.h" +#include "auth/credentials/credentials.h" + +static int net_user_add(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *lnet_ctx; + struct libnet_CreateUser r; + char *user_name; + + /* command line argument preparation */ + switch (argc) { + case 0: + return net_user_usage(ctx, argc, argv); + break; + case 1: + user_name = talloc_strdup(ctx, argv[0]); + break; + default: + return net_user_usage(ctx, argc, argv); + } + + /* libnet context init and its params */ + lnet_ctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!lnet_ctx) return -1; + + lnet_ctx->cred = ctx->credentials; + + /* calling CreateUser function */ + r.in.user_name = user_name; + r.in.domain_name = cli_credentials_get_domain(lnet_ctx->cred); + + status = libnet_CreateUser(lnet_ctx, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to add user account: %s\n", + r.out.error_string)); + return -1; + } + + talloc_free(lnet_ctx); + return 0; +} + +static int net_user_delete(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *lnet_ctx; + struct libnet_DeleteUser r; + char *user_name; + + /* command line argument preparation */ + switch (argc) { + case 0: + return net_user_usage(ctx, argc, argv); + break; + case 1: + user_name = talloc_strdup(ctx, argv[0]); + break; + default: + return net_user_usage(ctx, argc, argv); + } + + /* libnet context init and its params */ + lnet_ctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!lnet_ctx) return -1; + + lnet_ctx->cred = ctx->credentials; + + /* calling DeleteUser function */ + r.in.user_name = user_name; + r.in.domain_name = cli_credentials_get_domain(lnet_ctx->cred); + + status = libnet_DeleteUser(lnet_ctx, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to delete user account: %s\n", + r.out.error_string)); + return -1; + } + + talloc_free(lnet_ctx); + return 0; +} + + +static const struct net_functable net_user_functable[] = { + { "add", "create new user account\n", net_user_add, net_user_usage }, + { "delete", "delete an existing user account\n", net_user_delete, net_user_usage }, + { NULL, NULL } +}; + + +int net_user(struct net_context *ctx, int argc, const char **argv) +{ + return net_run_function(ctx, argc, argv, net_user_functable, net_user_usage); +} + + +int net_user_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net user <command> [options]\n"); + return 0; +} diff --git a/source4/utils/net/net_vampire.c b/source4/utils/net/net_vampire.c new file mode 100644 index 0000000000..14f6a07e4b --- /dev/null +++ b/source4/utils/net/net_vampire.c @@ -0,0 +1,181 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + + Copyright (C) 2004 Stefan Metzmacher <metze@samba.org> + Copyright (C) 2005 Andrew Bartlett <abartlet@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 "utils/net/net.h" +#include "libnet/libnet.h" +#include "librpc/gen_ndr/samr.h" +#include "auth/auth.h" +#include "param/param.h" +#include "lib/events/events.h" + +static int net_samdump_keytab_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net samdump keytab <keytab>\n"); + return 0; +} + +static int net_samdump_keytab_help(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("Dumps kerberos keys of a domain into a keytab.\n"); + return 0; +} + +static int net_samdump_keytab(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *libnetctx; + struct libnet_SamDump_keytab r; + + switch (argc) { + case 0: + return net_samdump_keytab_usage(ctx, argc, argv); + break; + case 1: + r.in.keytab_name = argv[0]; + break; + } + + libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!libnetctx) { + return -1; + } + libnetctx->cred = ctx->credentials; + + r.out.error_string = NULL; + r.in.machine_account = NULL; + r.in.binding_string = NULL; + + status = libnet_SamDump_keytab(libnetctx, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("libnet_SamDump returned %s: %s\n", + nt_errstr(status), + r.out.error_string)); + return -1; + } + + talloc_free(libnetctx); + + return 0; +} + +/* main function table */ +static const struct net_functable net_samdump_functable[] = { + {"keytab", "dump keys into a keytab\n", net_samdump_keytab, net_samdump_keytab_usage}, + {NULL, NULL, NULL, NULL} +}; + +int net_samdump(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *libnetctx; + struct libnet_SamDump r; + int rc; + + switch (argc) { + case 0: + break; + case 1: + default: + rc = net_run_function(ctx, argc, argv, net_samdump_functable, + net_samdump_usage); + return rc; + } + + libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!libnetctx) { + return -1; + } + libnetctx->cred = ctx->credentials; + + r.out.error_string = NULL; + r.in.machine_account = NULL; + r.in.binding_string = NULL; + + status = libnet_SamDump(libnetctx, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("libnet_SamDump returned %s: %s\n", + nt_errstr(status), + r.out.error_string)); + return -1; + } + + talloc_free(libnetctx); + + return 0; +} + +int net_samdump_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net samdump\n"); + d_printf("net samdump keytab <keytab>\n"); + return 0; +} + +int net_samdump_help(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("Dumps the sam of the domain we are joined to.\n"); + return 0; +} + +int net_samsync_ldb(struct net_context *ctx, int argc, const char **argv) +{ + NTSTATUS status; + struct libnet_context *libnetctx; + struct libnet_samsync_ldb r; + + libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); + if (!libnetctx) { + return -1; + } + libnetctx->cred = ctx->credentials; + + r.out.error_string = NULL; + r.in.machine_account = NULL; + r.in.binding_string = NULL; + + /* Needed to override the ACLs on ldb */ + r.in.session_info = system_session(libnetctx, ctx->lp_ctx); + + status = libnet_samsync_ldb(libnetctx, libnetctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("libnet_samsync_ldb returned %s: %s\n", + nt_errstr(status), + r.out.error_string)); + return -1; + } + + talloc_free(libnetctx); + + return 0; +} + +int net_samsync_ldb_usage(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("net samsync\n"); + return 0; +} + +int net_samsync_ldb_help(struct net_context *ctx, int argc, const char **argv) +{ + d_printf("Synchronise into the local ldb the SAM of a domain.\n"); + return 0; +} diff --git a/source4/utils/nmblookup.c b/source4/utils/nmblookup.c new file mode 100644 index 0000000000..a74ab5a42e --- /dev/null +++ b/source4/utils/nmblookup.c @@ -0,0 +1,381 @@ +/* + Unix SMB/CIFS implementation. + + NBT client - used to lookup netbios names + + Copyright (C) Andrew Tridgell 1994-2005 + Copyright (C) Jelmer Vernooij 2003 (Conversion to popt) + + 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 "lib/cmdline/popt_common.h" +#include "lib/socket/socket.h" +#include "lib/events/events.h" +#include "system/network.h" +#include "system/locale.h" +#include "lib/socket/netif.h" +#include "librpc/gen_ndr/nbt.h" +#include "libcli/nbt/libnbt.h" +#include "param/param.h" + +/* command line options */ +static struct { + const char *broadcast_address; + const char *unicast_address; + bool find_master; + bool wins_lookup; + bool node_status; + bool root_port; + bool lookup_by_ip; + bool case_sensitive; +} options; + +/* + clean any binary from a node name +*/ +static const char *clean_name(TALLOC_CTX *mem_ctx, const char *name) +{ + char *ret = talloc_strdup(mem_ctx, name); + int i; + for (i=0;ret[i];i++) { + if (!isprint((unsigned char)ret[i])) ret[i] = '.'; + } + return ret; +} + +/* + turn a node status flags field into a string +*/ +static char *node_status_flags(TALLOC_CTX *mem_ctx, uint16_t flags) +{ + char *ret; + const char *group = " "; + const char *type = "B"; + + if (flags & NBT_NM_GROUP) { + group = "<GROUP>"; + } + + switch (flags & NBT_NM_OWNER_TYPE) { + case NBT_NODE_B: + type = "B"; + break; + case NBT_NODE_P: + type = "P"; + break; + case NBT_NODE_M: + type = "M"; + break; + case NBT_NODE_H: + type = "H"; + break; + } + + ret = talloc_asprintf(mem_ctx, "%s %s", group, type); + + if (flags & NBT_NM_DEREGISTER) { + ret = talloc_asprintf_append_buffer(ret, " <DEREGISTERING>"); + } + if (flags & NBT_NM_CONFLICT) { + ret = talloc_asprintf_append_buffer(ret, " <CONFLICT>"); + } + if (flags & NBT_NM_ACTIVE) { + ret = talloc_asprintf_append_buffer(ret, " <ACTIVE>"); + } + if (flags & NBT_NM_PERMANENT) { + ret = talloc_asprintf_append_buffer(ret, " <PERMANENT>"); + } + + return ret; +} + +/* do a single node status */ +static bool do_node_status(struct nbt_name_socket *nbtsock, + const char *addr, uint16_t port) +{ + struct nbt_name_status io; + NTSTATUS status; + + io.in.name.name = "*"; + io.in.name.type = NBT_NAME_CLIENT; + io.in.name.scope = NULL; + io.in.dest_addr = addr; + io.in.dest_port = port; + io.in.timeout = 1; + io.in.retries = 2; + + status = nbt_name_status(nbtsock, nbtsock, &io); + if (NT_STATUS_IS_OK(status)) { + int i; + printf("Node status reply from %s\n", + io.out.reply_from); + for (i=0;i<io.out.status.num_names;i++) { + d_printf("\t%-16s <%02x> %s\n", + clean_name(nbtsock, io.out.status.names[i].name), + io.out.status.names[i].type, + node_status_flags(nbtsock, io.out.status.names[i].nb_flags)); + } + printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n", + io.out.status.statistics.unit_id[0], + io.out.status.statistics.unit_id[1], + io.out.status.statistics.unit_id[2], + io.out.status.statistics.unit_id[3], + io.out.status.statistics.unit_id[4], + io.out.status.statistics.unit_id[5]); + return true; + } + + return false; +} + +/* do a single node query */ +static NTSTATUS do_node_query(struct nbt_name_socket *nbtsock, + const char *addr, + uint16_t port, + const char *node_name, + enum nbt_name_type node_type, + bool broadcast) +{ + struct nbt_name_query io; + NTSTATUS status; + int i; + + io.in.name.name = node_name; + io.in.name.type = node_type; + io.in.name.scope = NULL; + io.in.dest_addr = addr; + io.in.dest_port = port; + io.in.broadcast = broadcast; + io.in.wins_lookup = options.wins_lookup; + io.in.timeout = 1; + io.in.retries = 2; + + status = nbt_name_query(nbtsock, nbtsock, &io); + NT_STATUS_NOT_OK_RETURN(status); + + for (i=0;i<io.out.num_addrs;i++) { + printf("%s %s<%02x>\n", + io.out.reply_addrs[i], + io.out.name.name, + io.out.name.type); + } + if (options.node_status && io.out.num_addrs > 0) { + do_node_status(nbtsock, io.out.reply_addrs[0], port); + } + + return status; +} + + +static bool process_one(struct loadparm_context *lp_ctx, struct event_context *ev, + struct interface *ifaces, const char *name, int nbt_port) +{ + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + enum nbt_name_type node_type = NBT_NAME_CLIENT; + char *node_name, *p; + struct socket_address *all_zero_addr; + struct nbt_name_socket *nbtsock; + NTSTATUS status = NT_STATUS_OK; + bool ret = true; + + if (!options.case_sensitive) { + name = strupper_talloc(tmp_ctx, name); + } + + if (options.find_master) { + node_type = NBT_NAME_MASTER; + if (*name == '-' || *name == '_') { + name = "\01\02__MSBROWSE__\02"; + node_type = NBT_NAME_MS; + } + } + + p = strchr(name, '#'); + if (p) { + node_name = talloc_strndup(tmp_ctx, name, PTR_DIFF(p,name)); + node_type = (enum nbt_name_type)strtol(p+1, NULL, 16); + } else { + node_name = talloc_strdup(tmp_ctx, name); + } + + nbtsock = nbt_name_socket_init(tmp_ctx, ev, lp_iconv_convenience(lp_ctx)); + + if (options.root_port) { + all_zero_addr = socket_address_from_strings(tmp_ctx, nbtsock->sock->backend_name, + "0.0.0.0", NBT_NAME_SERVICE_PORT); + + if (!all_zero_addr) { + talloc_free(tmp_ctx); + return false; + } + + status = socket_listen(nbtsock->sock, all_zero_addr, 0, 0); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to bind to local port 137 - %s\n", nt_errstr(status)); + talloc_free(tmp_ctx); + return false; + } + } + + if (options.lookup_by_ip) { + ret = do_node_status(nbtsock, name, nbt_port); + talloc_free(tmp_ctx); + return ret; + } + + if (options.broadcast_address) { + status = do_node_query(nbtsock, options.broadcast_address, nbt_port, + node_name, node_type, true); + } else if (options.unicast_address) { + status = do_node_query(nbtsock, options.unicast_address, + nbt_port, node_name, node_type, false); + } else { + int i, num_interfaces; + + num_interfaces = iface_count(ifaces); + for (i=0;i<num_interfaces;i++) { + const char *bcast = iface_n_bcast(ifaces, i); + if (bcast == NULL) continue; + status = do_node_query(nbtsock, bcast, nbt_port, + node_name, node_type, true); + if (NT_STATUS_IS_OK(status)) break; + } + } + + if (!NT_STATUS_IS_OK(status)) { + printf("Lookup failed - %s\n", nt_errstr(status)); + ret = false; + } + + talloc_free(tmp_ctx); + return ret; +} + +/* + main program +*/ +int main(int argc, const char *argv[]) +{ + bool ret = true; + struct interface *ifaces; + struct event_context *ev; + poptContext pc; + int opt; + enum { + OPT_BROADCAST_ADDRESS = 1000, + OPT_UNICAST_ADDRESS, + OPT_FIND_MASTER, + OPT_WINS_LOOKUP, + OPT_NODE_STATUS, + OPT_ROOT_PORT, + OPT_LOOKUP_BY_IP, + OPT_CASE_SENSITIVE + }; + struct poptOption long_options[] = { + POPT_AUTOHELP + { "broadcast", 'B', POPT_ARG_STRING, NULL, OPT_BROADCAST_ADDRESS, + "Specify address to use for broadcasts", "BROADCAST-ADDRESS" }, + + { "unicast", 'U', POPT_ARG_STRING, NULL, OPT_UNICAST_ADDRESS, + "Specify address to use for unicast", NULL }, + + { "master-browser", 'M', POPT_ARG_NONE, NULL, OPT_FIND_MASTER, + "Search for a master browser", NULL }, + + { "wins", 'W', POPT_ARG_NONE, NULL, OPT_WINS_LOOKUP, + "Do a WINS lookup", NULL }, + + { "status", 'S', POPT_ARG_NONE, NULL, OPT_NODE_STATUS, + "Lookup node status as well", NULL }, + + { "root-port", 'r', POPT_ARG_NONE, NULL, OPT_ROOT_PORT, + "Use root port 137 (Win95 only replies to this)", NULL }, + + { "lookup-by-ip", 'A', POPT_ARG_NONE, NULL, OPT_LOOKUP_BY_IP, + "Do a node status on <name> as an IP Address", NULL }, + + { "case-sensitive", 0, POPT_ARG_NONE, NULL, OPT_CASE_SENSITIVE, + "Don't uppercase the name before sending", NULL }, + + POPT_COMMON_SAMBA + { 0, 0, 0, 0 } + }; + + pc = poptGetContext("nmblookup", argc, argv, long_options, + POPT_CONTEXT_KEEP_FIRST); + + poptSetOtherOptionHelp(pc, "<NODE> ..."); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + case OPT_BROADCAST_ADDRESS: + options.broadcast_address = poptGetOptArg(pc); + break; + case OPT_UNICAST_ADDRESS: + options.unicast_address = poptGetOptArg(pc); + break; + case OPT_FIND_MASTER: + options.find_master = true; + break; + case OPT_WINS_LOOKUP: + options.wins_lookup = true; + break; + case OPT_NODE_STATUS: + options.node_status = true; + break; + case OPT_ROOT_PORT: + options.root_port = true; + break; + case OPT_LOOKUP_BY_IP: + options.lookup_by_ip = true; + break; + case OPT_CASE_SENSITIVE: + options.case_sensitive = true; + break; + } + } + + /* swallow argv[0] */ + poptGetArg(pc); + + if(!poptPeekArg(pc)) { + poptPrintUsage(pc, stderr, 0); + exit(1); + } + + load_interfaces(NULL, lp_interfaces(cmdline_lp_ctx), &ifaces); + + ev = s4_event_context_init(talloc_autofree_context()); + + while (poptPeekArg(pc)) { + const char *name = poptGetArg(pc); + + ret &= process_one(cmdline_lp_ctx, ev, ifaces, name, lp_nbt_port(cmdline_lp_ctx)); + } + + talloc_free(ev); + + talloc_free(ifaces); + + poptFreeContext(pc); + + if (!ret) { + return 1; + } + + return 0; +} diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c new file mode 100644 index 0000000000..6a6302837e --- /dev/null +++ b/source4/utils/ntlm_auth.c @@ -0,0 +1,1159 @@ +/* + Unix SMB/CIFS implementation. + + Winbind status program. + + Copyright (C) Tim Potter 2000-2003 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004 + Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 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 "includes.h" +#include "system/filesys.h" +#include "lib/cmdline/popt_common.h" +#include "lib/ldb/include/ldb.h" +#include "auth/credentials/credentials.h" +#include "auth/gensec/gensec.h" +#include "auth/auth.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "auth/auth_sam.h" +#include "auth/ntlm/ntlm_check.h" +#include "pstring.h" +#include "libcli/auth/libcli_auth.h" +#include "libcli/security/security.h" +#include "lib/events/events.h" +#include "lib/messaging/messaging.h" +#include "lib/messaging/irpc.h" +#include "auth/ntlmssp/ntlmssp.h" +#include "param/param.h" + +#define INITIAL_BUFFER_SIZE 300 +#define MAX_BUFFER_SIZE 63000 + +enum stdio_helper_mode { + SQUID_2_4_BASIC, + SQUID_2_5_BASIC, + SQUID_2_5_NTLMSSP, + NTLMSSP_CLIENT_1, + GSS_SPNEGO_CLIENT, + GSS_SPNEGO_SERVER, + NTLM_SERVER_1, + NUM_HELPER_MODES +}; + +#define NTLM_AUTH_FLAG_USER_SESSION_KEY 0x0004 +#define NTLM_AUTH_FLAG_LMKEY 0x0008 + + +typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private, + unsigned int mux_id, void **private2); + +static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private, + unsigned int mux_id, void **private2); + +static void manage_gensec_request (enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private, + unsigned int mux_id, void **private2); + +static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private, + unsigned int mux_id, void **private2); + +static void manage_squid_request(struct loadparm_context *lp_ctx, + enum stdio_helper_mode helper_mode, + stdio_helper_function fn, void **private2); + +static const struct { + enum stdio_helper_mode mode; + const char *name; + stdio_helper_function fn; +} stdio_helper_protocols[] = { + { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request}, + { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request}, + { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_gensec_request}, + { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gensec_request}, + { GSS_SPNEGO_SERVER, "gss-spnego", manage_gensec_request}, + { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_gensec_request}, + { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request}, + { NUM_HELPER_MODES, NULL, NULL} +}; + +extern int winbindd_fd; + +static const char *opt_username; +static const char *opt_domain; +static const char *opt_workstation; +static const char *opt_password; +static int opt_multiplex; +static int use_cached_creds; + + +static void mux_printf(unsigned int mux_id, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); + +static void mux_printf(unsigned int mux_id, const char *format, ...) +{ + va_list ap; + + if (opt_multiplex) { + x_fprintf(x_stdout, "%d ", mux_id); + } + + va_start(ap, format); + x_vfprintf(x_stdout, format, ap); + va_end(ap); +} + + + +/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the + form DOMAIN/user into a domain and a user */ + +static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain, + fstring user, char winbind_separator) +{ + + char *p = strchr(domuser, winbind_separator); + + if (!p) { + return false; + } + + fstrcpy(user, p+1); + fstrcpy(domain, domuser); + domain[PTR_DIFF(p, domuser)] = 0; + + return true; +} + +/** + * Decode a base64 string into a DATA_BLOB - simple and slow algorithm + **/ +static DATA_BLOB base64_decode_data_blob(TALLOC_CTX *mem_ctx, const char *s) +{ + DATA_BLOB ret = data_blob_talloc(mem_ctx, s, strlen(s)+1); + ret.length = ldb_base64_decode((char *)ret.data); + return ret; +} + +/** + * Encode a base64 string into a talloc()ed string caller to free. + **/ +static char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data) +{ + return ldb_base64_encode(mem_ctx, (const char *)data.data, data.length); +} + +/** + * Decode a base64 string in-place - wrapper for the above + **/ +static void base64_decode_inplace(char *s) +{ + ldb_base64_decode(s); +} + + + +/* Authenticate a user with a plaintext password */ + +static bool check_plaintext_auth(const char *user, const char *pass, + bool stdout_diagnostics) +{ + return (strcmp(pass, opt_password) == 0); +} + +/* authenticate a user with an encrypted username/password */ + +static NTSTATUS local_pw_check_specified(struct loadparm_context *lp_ctx, + const char *username, + const char *domain, + const char *workstation, + const DATA_BLOB *challenge, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + uint32_t flags, + DATA_BLOB *lm_session_key, + DATA_BLOB *user_session_key, + char **error_string, + char **unix_name) +{ + NTSTATUS nt_status; + struct samr_Password lm_pw, nt_pw; + struct samr_Password *lm_pwd, *nt_pwd; + TALLOC_CTX *mem_ctx = talloc_init("local_pw_check_specified"); + if (!mem_ctx) { + nt_status = NT_STATUS_NO_MEMORY; + } else { + + E_md4hash(opt_password, nt_pw.hash); + if (E_deshash(opt_password, lm_pw.hash)) { + lm_pwd = &lm_pw; + } else { + lm_pwd = NULL; + } + nt_pwd = &nt_pw; + + + nt_status = ntlm_password_check(mem_ctx, + lp_ctx, + MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | + MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, + challenge, + lm_response, + nt_response, + username, + username, + domain, + lm_pwd, nt_pwd, user_session_key, lm_session_key); + + if (NT_STATUS_IS_OK(nt_status)) { + if (unix_name) { + asprintf(unix_name, + "%s%c%s", domain, + *lp_winbind_separator(lp_ctx), + username); + } + } else { + DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", + domain, username, workstation, + nt_errstr(nt_status))); + } + talloc_free(mem_ctx); + } + if (error_string) { + *error_string = strdup(nt_errstr(nt_status)); + } + return nt_status; + + +} + +static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private, + unsigned int mux_id, void **private2) +{ + char *user, *pass; + user=buf; + + pass = memchr(buf, ' ', length); + if (!pass) { + DEBUG(2, ("Password not found. Denying access\n")); + mux_printf(mux_id, "ERR\n"); + return; + } + *pass='\0'; + pass++; + + if (stdio_helper_mode == SQUID_2_5_BASIC) { + rfc1738_unescape(user); + rfc1738_unescape(pass); + } + + if (check_plaintext_auth(user, pass, false)) { + mux_printf(mux_id, "OK\n"); + } else { + mux_printf(mux_id, "ERR\n"); + } +} + +/* This is a bit hairy, but the basic idea is to do a password callback + to the calling application. The callback comes from within gensec */ + +static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private, + unsigned int mux_id, void **password) +{ + DATA_BLOB in; + if (strlen(buf) < 2) { + DEBUG(1, ("query [%s] invalid", buf)); + mux_printf(mux_id, "BH Query invalid\n"); + return; + } + + if (strlen(buf) > 3) { + in = base64_decode_data_blob(NULL, buf + 3); + } else { + in = data_blob(NULL, 0); + } + + if (strncmp(buf, "PW ", 3) == 0) { + + *password = talloc_strndup(*private /* hopefully the right gensec context, useful to use for talloc */, + (const char *)in.data, in.length); + + if (*password == NULL) { + DEBUG(1, ("Out of memory\n")); + mux_printf(mux_id, "BH Out of memory\n"); + data_blob_free(&in); + return; + } + + mux_printf(mux_id, "OK\n"); + data_blob_free(&in); + return; + } + DEBUG(1, ("Asked for (and expected) a password\n")); + mux_printf(mux_id, "BH Expected a password\n"); + data_blob_free(&in); +} + +/** + * Callback for password credentials. This is not async, and when + * GENSEC and the credentials code is made async, it will look rather + * different. + */ + +static const char *get_password(struct cli_credentials *credentials) +{ + char *password = NULL; + + /* Ask for a password */ + mux_printf((unsigned int)(uintptr_t)credentials->priv_data, "PW\n"); + credentials->priv_data = NULL; + + manage_squid_request(cmdline_lp_ctx, NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, (void **)&password); + return password; +} + +/** + Check if a string is part of a list. +**/ +static bool in_list(const char *s, const char *list, bool casesensitive) +{ + char *tok; + size_t tok_len = 1024; + const char *p=list; + + if (!list) + return false; + + tok = (char *)malloc(tok_len); + if (!tok) { + return false; + } + + while (next_token(&p, tok, LIST_SEP, tok_len)) { + if ((casesensitive?strcmp:strcasecmp_m)(tok,s) == 0) { + free(tok); + return true; + } + } + free(tok); + return false; +} + +static void gensec_want_feature_list(struct gensec_security *state, char* feature_list) +{ + if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) { + DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n")); + gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY); + } + if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) { + DEBUG(10, ("want GENSEC_FEATURE_SIGN\n")); + gensec_want_feature(state, GENSEC_FEATURE_SIGN); + } + if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) { + DEBUG(10, ("want GENSEC_FEATURE_SEAL\n")); + gensec_want_feature(state, GENSEC_FEATURE_SEAL); + } +} + +static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private, + unsigned int mux_id, void **private2) +{ + DATA_BLOB in; + DATA_BLOB out = data_blob(NULL, 0); + char *out_base64 = NULL; + const char *reply_arg = NULL; + struct gensec_ntlm_state { + struct gensec_security *gensec_state; + const char *set_password; + }; + struct gensec_ntlm_state *state; + struct event_context *ev; + struct messaging_context *msg; + + NTSTATUS nt_status; + bool first = false; + const char *reply_code; + struct cli_credentials *creds; + + static char *want_feature_list = NULL; + static DATA_BLOB session_key; + + TALLOC_CTX *mem_ctx; + + if (*private) { + state = (struct gensec_ntlm_state *)*private; + } else { + state = talloc_zero(NULL, struct gensec_ntlm_state); + if (!state) { + mux_printf(mux_id, "BH No Memory\n"); + exit(1); + } + *private = state; + if (opt_password) { + state->set_password = opt_password; + } + } + + if (strlen(buf) < 2) { + DEBUG(1, ("query [%s] invalid", buf)); + mux_printf(mux_id, "BH Query invalid\n"); + return; + } + + if (strlen(buf) > 3) { + if(strncmp(buf, "SF ", 3) == 0) { + DEBUG(10, ("Setting flags to negotiate\n")); + talloc_free(want_feature_list); + want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3); + mux_printf(mux_id, "OK\n"); + return; + } + in = base64_decode_data_blob(NULL, buf + 3); + } else { + in = data_blob(NULL, 0); + } + + if (strncmp(buf, "YR", 2) == 0) { + if (state->gensec_state) { + talloc_free(state->gensec_state); + state->gensec_state = NULL; + } + } else if ( (strncmp(buf, "OK", 2) == 0)) { + /* Just return BH, like ntlm_auth from Samba 3 does. */ + mux_printf(mux_id, "BH Command expected\n"); + data_blob_free(&in); + return; + } else if ( (strncmp(buf, "TT ", 3) != 0) && + (strncmp(buf, "KK ", 3) != 0) && + (strncmp(buf, "AF ", 3) != 0) && + (strncmp(buf, "NA ", 3) != 0) && + (strncmp(buf, "UG", 2) != 0) && + (strncmp(buf, "PW ", 3) != 0) && + (strncmp(buf, "GK", 2) != 0) && + (strncmp(buf, "GF", 2) != 0)) { + DEBUG(1, ("SPNEGO request [%s] invalid\n", buf)); + mux_printf(mux_id, "BH SPNEGO request invalid\n"); + data_blob_free(&in); + return; + } + + ev = s4_event_context_init(state); + if (!ev) { + exit(1); + } + /* setup gensec */ + if (!(state->gensec_state)) { + switch (stdio_helper_mode) { + case GSS_SPNEGO_CLIENT: + case NTLMSSP_CLIENT_1: + /* setup the client side */ + + nt_status = gensec_client_start(NULL, &state->gensec_state, ev, lp_ctx); + if (!NT_STATUS_IS_OK(nt_status)) { + exit(1); + } + + break; + case GSS_SPNEGO_SERVER: + case SQUID_2_5_NTLMSSP: + msg = messaging_client_init(state, lp_messaging_path(state, lp_ctx), + lp_iconv_convenience(lp_ctx), ev); + if (!msg) { + exit(1); + } + if (!NT_STATUS_IS_OK(gensec_server_start(state, ev, lp_ctx, msg, &state->gensec_state))) { + exit(1); + } + break; + default: + abort(); + } + + creds = cli_credentials_init(state->gensec_state); + cli_credentials_set_conf(creds, lp_ctx); + if (opt_username) { + cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED); + } + if (opt_domain) { + cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED); + } + if (state->set_password) { + cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED); + } else { + cli_credentials_set_password_callback(creds, get_password); + creds->priv_data = (void*)(uintptr_t)mux_id; + } + if (opt_workstation) { + cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED); + } + + switch (stdio_helper_mode) { + case GSS_SPNEGO_SERVER: + case SQUID_2_5_NTLMSSP: + cli_credentials_set_machine_account(creds, lp_ctx); + break; + default: + break; + } + + gensec_set_credentials(state->gensec_state, creds); + gensec_want_feature_list(state->gensec_state, want_feature_list); + + switch (stdio_helper_mode) { + case GSS_SPNEGO_CLIENT: + case GSS_SPNEGO_SERVER: + nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO); + if (!in.length) { + first = true; + } + break; + case NTLMSSP_CLIENT_1: + if (!in.length) { + first = true; + } + /* fall through */ + case SQUID_2_5_NTLMSSP: + nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP); + break; + default: + abort(); + } + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status))); + mux_printf(mux_id, "BH GENSEC mech failed to start\n"); + return; + } + + } + + /* update */ + mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx"); + + if (strncmp(buf, "PW ", 3) == 0) { + state->set_password = talloc_strndup(state, + (const char *)in.data, + in.length); + + cli_credentials_set_password(gensec_get_credentials(state->gensec_state), + state->set_password, + CRED_SPECIFIED); + mux_printf(mux_id, "OK\n"); + data_blob_free(&in); + talloc_free(mem_ctx); + return; + } + + if (strncmp(buf, "UG", 2) == 0) { + int i; + char *grouplist = NULL; + struct auth_session_info *session_info; + + nt_status = gensec_session_info(state->gensec_state, &session_info); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("gensec_session_info failed: %s\n", nt_errstr(nt_status))); + mux_printf(mux_id, "BH %s\n", nt_errstr(nt_status)); + data_blob_free(&in); + talloc_free(mem_ctx); + return; + } + + /* get the string onto the context */ + grouplist = talloc_strdup(mem_ctx, ""); + + for (i=0; i<session_info->security_token->num_sids; i++) { + struct security_token *token = session_info->security_token; + const char *sidstr = dom_sid_string(session_info, + token->sids[i]); + grouplist = talloc_asprintf_append_buffer(grouplist, "%s,", sidstr); + } + + mux_printf(mux_id, "GL %s\n", grouplist); + talloc_free(session_info); + data_blob_free(&in); + talloc_free(mem_ctx); + return; + } + + if (strncmp(buf, "GK", 2) == 0) { + char *base64_key; + DEBUG(10, ("Requested session key\n")); + nt_status = gensec_session_key(state->gensec_state, &session_key); + if(!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status))); + mux_printf(mux_id, "BH No session key\n"); + talloc_free(mem_ctx); + return; + } else { + base64_key = base64_encode_data_blob(state, session_key); + mux_printf(mux_id, "GK %s\n", base64_key); + talloc_free(base64_key); + } + talloc_free(mem_ctx); + return; + } + + if (strncmp(buf, "GF", 2) == 0) { + struct gensec_ntlmssp_state *gensec_ntlmssp_state; + uint32_t neg_flags; + + gensec_ntlmssp_state = talloc_get_type(state->gensec_state->private_data, + struct gensec_ntlmssp_state); + neg_flags = gensec_ntlmssp_state->neg_flags; + + DEBUG(10, ("Requested negotiated feature flags\n")); + mux_printf(mux_id, "GF 0x%08x\n", neg_flags); + return; + } + + nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out); + + /* don't leak 'bad password'/'no such user' info to the network client */ + nt_status = auth_nt_status_squash(nt_status); + + if (out.length) { + out_base64 = base64_encode_data_blob(mem_ctx, out); + } else { + out_base64 = NULL; + } + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + reply_arg = "*"; + if (first) { + reply_code = "YR"; + } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) { + reply_code = "KK"; + } else if (state->gensec_state->gensec_role == GENSEC_SERVER) { + reply_code = "TT"; + } else { + abort(); + } + + + } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) { + reply_code = "BH NT_STATUS_ACCESS_DENIED"; + reply_arg = nt_errstr(nt_status); + DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); + } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) { + reply_code = "BH NT_STATUS_UNSUCCESSFUL"; + reply_arg = nt_errstr(nt_status); + DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); + } else if (!NT_STATUS_IS_OK(nt_status)) { + reply_code = "NA"; + reply_arg = nt_errstr(nt_status); + DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); + } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) { + struct auth_session_info *session_info; + + nt_status = gensec_session_info(state->gensec_state, &session_info); + if (!NT_STATUS_IS_OK(nt_status)) { + reply_code = "BH Failed to retrive session info"; + reply_arg = nt_errstr(nt_status); + DEBUG(1, ("GENSEC failed to retreive the session info: %s\n", nt_errstr(nt_status))); + } else { + + reply_code = "AF"; + reply_arg = talloc_asprintf(state->gensec_state, + "%s%s%s", session_info->server_info->domain_name, + lp_winbind_separator(lp_ctx), session_info->server_info->account_name); + talloc_free(session_info); + } + } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) { + reply_code = "AF"; + reply_arg = out_base64; + } else { + abort(); + } + + switch (stdio_helper_mode) { + case GSS_SPNEGO_SERVER: + mux_printf(mux_id, "%s %s %s\n", reply_code, + out_base64 ? out_base64 : "*", + reply_arg ? reply_arg : "*"); + break; + default: + if (out_base64) { + mux_printf(mux_id, "%s %s\n", reply_code, out_base64); + } else if (reply_arg) { + mux_printf(mux_id, "%s %s\n", reply_code, reply_arg); + } else { + mux_printf(mux_id, "%s\n", reply_code); + } + } + + talloc_free(mem_ctx); + return; +} + +static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private, + unsigned int mux_id, void **private2) +{ + char *request, *parameter; + static DATA_BLOB challenge; + static DATA_BLOB lm_response; + static DATA_BLOB nt_response; + static char *full_username; + static char *username; + static char *domain; + static char *plaintext_password; + static bool ntlm_server_1_user_session_key; + static bool ntlm_server_1_lm_session_key; + + if (strequal(buf, ".")) { + if (!full_username && !username) { + mux_printf(mux_id, "Error: No username supplied!\n"); + } else if (plaintext_password) { + /* handle this request as plaintext */ + if (!full_username) { + if (asprintf(&full_username, "%s%c%s", domain, *lp_winbind_separator(lp_ctx), username) == -1) { + mux_printf(mux_id, "Error: Out of memory in asprintf!\n.\n"); + return; + } + } + if (check_plaintext_auth(full_username, plaintext_password, false)) { + mux_printf(mux_id, "Authenticated: Yes\n"); + } else { + mux_printf(mux_id, "Authenticated: No\n"); + } + } else if (!lm_response.data && !nt_response.data) { + mux_printf(mux_id, "Error: No password supplied!\n"); + } else if (!challenge.data) { + mux_printf(mux_id, "Error: No lanman-challenge supplied!\n"); + } else { + char *error_string = NULL; + DATA_BLOB lm_key; + DATA_BLOB user_session_key; + uint32_t flags = 0; + + if (full_username && !username) { + fstring fstr_user; + fstring fstr_domain; + + if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain, + *lp_winbind_separator(lp_ctx))) { + /* username might be 'tainted', don't print into our new-line deleimianted stream */ + mux_printf(mux_id, "Error: Could not parse into domain and username\n"); + } + SAFE_FREE(username); + SAFE_FREE(domain); + username = smb_xstrdup(fstr_user); + domain = smb_xstrdup(fstr_domain); + } + + if (!domain) { + domain = smb_xstrdup(lp_workgroup(lp_ctx)); + } + + if (ntlm_server_1_lm_session_key) + flags |= NTLM_AUTH_FLAG_LMKEY; + + if (ntlm_server_1_user_session_key) + flags |= NTLM_AUTH_FLAG_USER_SESSION_KEY; + + if (!NT_STATUS_IS_OK( + local_pw_check_specified(lp_ctx, + username, + domain, + lp_netbios_name(lp_ctx), + &challenge, + &lm_response, + &nt_response, + flags, + &lm_key, + &user_session_key, + &error_string, + NULL))) { + + mux_printf(mux_id, "Authenticated: No\n"); + mux_printf(mux_id, "Authentication-Error: %s\n.\n", error_string); + SAFE_FREE(error_string); + } else { + static char zeros[16]; + char *hex_lm_key; + char *hex_user_session_key; + + mux_printf(mux_id, "Authenticated: Yes\n"); + + if (ntlm_server_1_lm_session_key + && lm_key.length + && (memcmp(zeros, lm_key.data, + lm_key.length) != 0)) { + hex_encode(lm_key.data, + lm_key.length, + &hex_lm_key); + mux_printf(mux_id, "LANMAN-Session-Key: %s\n", hex_lm_key); + SAFE_FREE(hex_lm_key); + } + + if (ntlm_server_1_user_session_key + && user_session_key.length + && (memcmp(zeros, user_session_key.data, + user_session_key.length) != 0)) { + hex_encode(user_session_key.data, + user_session_key.length, + &hex_user_session_key); + mux_printf(mux_id, "User-Session-Key: %s\n", hex_user_session_key); + SAFE_FREE(hex_user_session_key); + } + } + } + /* clear out the state */ + challenge = data_blob(NULL, 0); + nt_response = data_blob(NULL, 0); + lm_response = data_blob(NULL, 0); + SAFE_FREE(full_username); + SAFE_FREE(username); + SAFE_FREE(domain); + SAFE_FREE(plaintext_password); + ntlm_server_1_user_session_key = false; + ntlm_server_1_lm_session_key = false; + mux_printf(mux_id, ".\n"); + + return; + } + + request = buf; + + /* Indicates a base64 encoded structure */ + parameter = strstr(request, ":: "); + if (!parameter) { + parameter = strstr(request, ": "); + + if (!parameter) { + DEBUG(0, ("Parameter not found!\n")); + mux_printf(mux_id, "Error: Parameter not found!\n.\n"); + return; + } + + parameter[0] ='\0'; + parameter++; + parameter[0] ='\0'; + parameter++; + + } else { + parameter[0] ='\0'; + parameter++; + parameter[0] ='\0'; + parameter++; + parameter[0] ='\0'; + parameter++; + + base64_decode_inplace(parameter); + } + + if (strequal(request, "LANMAN-Challenge")) { + challenge = strhex_to_data_blob(parameter); + if (challenge.length != 8) { + mux_printf(mux_id, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n", + parameter, + (int)challenge.length); + challenge = data_blob(NULL, 0); + } + } else if (strequal(request, "NT-Response")) { + nt_response = strhex_to_data_blob(parameter); + if (nt_response.length < 24) { + mux_printf(mux_id, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n", + parameter, + (int)nt_response.length); + nt_response = data_blob(NULL, 0); + } + } else if (strequal(request, "LANMAN-Response")) { + lm_response = strhex_to_data_blob(parameter); + if (lm_response.length != 24) { + mux_printf(mux_id, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n", + parameter, + (int)lm_response.length); + lm_response = data_blob(NULL, 0); + } + } else if (strequal(request, "Password")) { + plaintext_password = smb_xstrdup(parameter); + } else if (strequal(request, "NT-Domain")) { + domain = smb_xstrdup(parameter); + } else if (strequal(request, "Username")) { + username = smb_xstrdup(parameter); + } else if (strequal(request, "Full-Username")) { + full_username = smb_xstrdup(parameter); + } else if (strequal(request, "Request-User-Session-Key")) { + ntlm_server_1_user_session_key = strequal(parameter, "Yes"); + } else if (strequal(request, "Request-LanMan-Session-Key")) { + ntlm_server_1_lm_session_key = strequal(parameter, "Yes"); + } else { + mux_printf(mux_id, "Error: Unknown request %s\n.\n", request); + } +} + +static void manage_squid_request(struct loadparm_context *lp_ctx, enum stdio_helper_mode helper_mode, + stdio_helper_function fn, void **private2) +{ + char *buf; + char tmp[INITIAL_BUFFER_SIZE+1]; + unsigned int mux_id = 0; + int length, buf_size = 0; + char *c; + struct mux_private { + unsigned int max_mux; + void **private_pointers; + }; + + static struct mux_private *mux_private; + static void *normal_private; + void **private; + + buf = talloc_strdup(NULL, ""); + + if (buf == NULL) { + DEBUG(0, ("Failed to allocate memory for reading the input " + "buffer.\n")); + x_fprintf(x_stdout, "ERR\n"); + return; + } + + do { + /* this is not a typo - x_fgets doesn't work too well under + * squid */ + if (fgets(tmp, INITIAL_BUFFER_SIZE, stdin) == NULL) { + if (ferror(stdin)) { + DEBUG(1, ("fgets() failed! dying..... errno=%d " + "(%s)\n", ferror(stdin), + strerror(ferror(stdin)))); + + exit(1); /* BIIG buffer */ + } + exit(0); + } + + buf = talloc_strdup_append_buffer(buf, tmp); + buf_size += INITIAL_BUFFER_SIZE; + + if (buf_size > MAX_BUFFER_SIZE) { + DEBUG(0, ("Invalid Request (too large)\n")); + x_fprintf(x_stdout, "ERR\n"); + talloc_free(buf); + return; + } + + c = strchr(buf, '\n'); + } while (c == NULL); + + *c = '\0'; + length = c-buf; + + DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length)); + + if (buf[0] == '\0') { + DEBUG(0, ("Invalid Request (empty)\n")); + x_fprintf(x_stdout, "ERR\n"); + talloc_free(buf); + return; + } + + if (opt_multiplex) { + if (sscanf(buf, "%u ", &mux_id) != 1) { + DEBUG(0, ("Invalid Request - no multiplex id\n")); + x_fprintf(x_stdout, "ERR\n"); + talloc_free(buf); + return; + } + if (!mux_private) { + mux_private = talloc(NULL, struct mux_private); + mux_private->max_mux = 0; + mux_private->private_pointers = NULL; + } + + c=strchr(buf,' '); + if (!c) { + DEBUG(0, ("Invalid Request - no data after multiplex id\n")); + x_fprintf(x_stdout, "ERR\n"); + talloc_free(buf); + return; + } + c++; + if (mux_id >= mux_private->max_mux) { + unsigned int prev_max = mux_private->max_mux; + mux_private->max_mux = mux_id + 1; + mux_private->private_pointers + = talloc_realloc(mux_private, + mux_private->private_pointers, + void *, mux_private->max_mux); + memset(&mux_private->private_pointers[prev_max], '\0', + (sizeof(*mux_private->private_pointers) * (mux_private->max_mux - prev_max))); + }; + + private = &mux_private->private_pointers[mux_id]; + } else { + c = buf; + private = &normal_private; + } + + fn(helper_mode, lp_ctx, c, length, private, mux_id, private2); + talloc_free(buf); +} + +static void squid_stream(struct loadparm_context *lp_ctx, + enum stdio_helper_mode stdio_mode, + stdio_helper_function fn) { + /* initialize FDescs */ + x_setbuf(x_stdout, NULL); + x_setbuf(x_stderr, NULL); + while(1) { + manage_squid_request(lp_ctx, stdio_mode, fn, NULL); + } +} + + +/* Main program */ + +enum { + OPT_USERNAME = 1000, + OPT_DOMAIN, + OPT_WORKSTATION, + OPT_CHALLENGE, + OPT_RESPONSE, + OPT_LM, + OPT_NT, + OPT_PASSWORD, + OPT_LM_KEY, + OPT_USER_SESSION_KEY, + OPT_DIAGNOSTICS, + OPT_REQUIRE_MEMBERSHIP, + OPT_MULTIPLEX, + OPT_USE_CACHED_CREDS, +}; + +int main(int argc, const char **argv) +{ + static const char *helper_protocol; + int opt; + + poptContext pc; + + /* NOTE: DO NOT change this interface without considering the implications! + This is an external interface, which other programs will use to interact + with this helper. + */ + + /* We do not use single-letter command abbreviations, because they harm future + interface stability. */ + + struct poptOption long_options[] = { + POPT_AUTOHELP + { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"}, + { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"}, + { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"}, + { "username", 0, POPT_ARG_STRING, &opt_username, OPT_PASSWORD, "Username"}, + { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"}, + { "multiplex", 0, POPT_ARG_NONE, &opt_multiplex, OPT_MULTIPLEX, "Multiplex Mode"}, + { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "silently ignored for compatibility reasons"}, + POPT_COMMON_SAMBA + POPT_COMMON_VERSION + { NULL } + }; + + /* Samba client initialisation */ + + setup_logging(NULL, DEBUG_STDERR); + + /* Parse options */ + + pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0); + + /* Parse command line options */ + + if (argc == 1) { + poptPrintHelp(pc, stderr, 0); + return 1; + } + + pc = poptGetContext(NULL, argc, (const char **)argv, long_options, + POPT_CONTEXT_KEEP_FIRST); + + while((opt = poptGetNextOpt(pc)) != -1) { + if (opt < -1) { + break; + } + } + if (opt < -1) { + fprintf(stderr, "%s: %s\n", + poptBadOption(pc, POPT_BADOPTION_NOALIAS), + poptStrerror(opt)); + return 1; + } + + gensec_init(cmdline_lp_ctx); + + if (opt_domain == NULL) { + opt_domain = lp_workgroup(cmdline_lp_ctx); + } + + if (helper_protocol) { + int i; + for (i=0; i<NUM_HELPER_MODES; i++) { + if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) { + squid_stream(cmdline_lp_ctx, stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn); + exit(0); + } + } + x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol); + + for (i=0; i<NUM_HELPER_MODES; i++) { + x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name); + } + + exit(1); + } + + if (!opt_username) { + x_fprintf(x_stderr, "username must be specified!\n\n"); + poptPrintHelp(pc, stderr, 0); + exit(1); + } + + if (opt_workstation == NULL) { + opt_workstation = lp_netbios_name(cmdline_lp_ctx); + } + + if (!opt_password) { + opt_password = getpass("password: "); + } + + { + char *user; + + asprintf(&user, "%s%c%s", opt_domain, *lp_winbind_separator(cmdline_lp_ctx), opt_username); + if (!check_plaintext_auth(user, opt_password, true)) { + return 1; + } + } + + /* Exit code */ + + poptFreeContext(pc); + return 0; +} diff --git a/source4/utils/oLschema2ldif.c b/source4/utils/oLschema2ldif.c new file mode 100644 index 0000000000..6c4e6a9c80 --- /dev/null +++ b/source4/utils/oLschema2ldif.c @@ -0,0 +1,604 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: ldb + * + * Component: oLschema2ldif + * + * Description: utility to convert an OpenLDAP schema into AD LDIF + * + * Author: Simo Sorce + */ + +#include "includes.h" +#include "ldb_includes.h" +#include "tools/cmdline.h" +#include "dsdb/samdb/samdb.h" + +#define SCHEMA_UNKNOWN 0 +#define SCHEMA_NAME 1 +#define SCHEMA_SUP 2 +#define SCHEMA_STRUCTURAL 3 +#define SCHEMA_ABSTRACT 4 +#define SCHEMA_AUXILIARY 5 +#define SCHEMA_MUST 6 +#define SCHEMA_MAY 7 +#define SCHEMA_SINGLE_VALUE 8 +#define SCHEMA_EQUALITY 9 +#define SCHEMA_ORDERING 10 +#define SCHEMA_SUBSTR 11 +#define SCHEMA_SYNTAX 12 +#define SCHEMA_DESC 13 + +struct schema_conv { + int count; + int failures; +}; + +struct schema_token { + int type; + char *value; +}; + +struct ldb_context *ldb_ctx; +struct ldb_dn *basedn; + +static int check_braces(const char *string) +{ + int b; + char *c; + + b = 0; + if ((c = strchr(string, '(')) == NULL) { + return -1; + } + b++; + c++; + while (b) { + c = strpbrk(c, "()"); + if (c == NULL) return 1; + if (*c == '(') b++; + if (*c == ')') b--; + c++; + } + return 0; +} + +static char *skip_spaces(char *string) { + return (string + strspn(string, " \t\n")); +} + +static int add_multi_string(struct ldb_message *msg, const char *attr, char *values) +{ + char *c; + char *s; + int n; + + c = skip_spaces(values); + while (*c) { + n = strcspn(c, " \t$"); + s = talloc_strndup(msg, c, n); + if (ldb_msg_add_string(msg, attr, s) != 0) { + return -1; + } + c += n; + c += strspn(c, " \t$"); + } + + return 0; +} + +#define MSG_ADD_STRING(a, v) do { if (ldb_msg_add_string(msg, a, v) != 0) goto failed; } while(0) +#define MSG_ADD_M_STRING(a, v) do { if (add_multi_string(msg, a, v) != 0) goto failed; } while(0) + +static char *get_def_value(TALLOC_CTX *ctx, char **string) +{ + char *c = *string; + char *value; + int n; + + if (*c == '\'') { + c++; + n = strcspn(c, "\'"); + value = talloc_strndup(ctx, c, n); + c += n; + c++; /* skip closing \' */ + } else { + n = strcspn(c, " \t\n"); + value = talloc_strndup(ctx, c, n); + c += n; + } + *string = c; + + return value; +} + +static struct schema_token *get_next_schema_token(TALLOC_CTX *ctx, char **string) +{ + char *c = skip_spaces(*string); + char *type; + struct schema_token *token; + int n; + + token = talloc(ctx, struct schema_token); + + n = strcspn(c, " \t\n"); + type = talloc_strndup(token, c, n); + c += n; + c = skip_spaces(c); + + if (strcasecmp("NAME", type) == 0) { + talloc_free(type); + token->type = SCHEMA_NAME; + /* we do not support aliases so we get only the first name given and skip others */ + if (*c == '(') { + char *s = strchr(c, ')'); + if (s == NULL) return NULL; + s = skip_spaces(s); + *string = s; + + c++; + c = skip_spaces(c); + } + + token->value = get_def_value(ctx, &c); + + if (*string < c) { /* single name */ + c = skip_spaces(c); + *string = c; + } + return token; + } + if (strcasecmp("SUP", type) == 0) { + talloc_free(type); + token->type = SCHEMA_SUP; + + if (*c == '(') { + c++; + n = strcspn(c, ")"); + token->value = talloc_strndup(ctx, c, n); + c += n; + c++; + } else { + token->value = get_def_value(ctx, &c); + } + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("STRUCTURAL", type) == 0) { + talloc_free(type); + token->type = SCHEMA_STRUCTURAL; + *string = c; + return token; + } + + if (strcasecmp("ABSTRACT", type) == 0) { + talloc_free(type); + token->type = SCHEMA_ABSTRACT; + *string = c; + return token; + } + + if (strcasecmp("AUXILIARY", type) == 0) { + talloc_free(type); + token->type = SCHEMA_AUXILIARY; + *string = c; + return token; + } + + if (strcasecmp("MUST", type) == 0) { + talloc_free(type); + token->type = SCHEMA_MUST; + + if (*c == '(') { + c++; + n = strcspn(c, ")"); + token->value = talloc_strndup(ctx, c, n); + c += n; + c++; + } else { + token->value = get_def_value(ctx, &c); + } + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("MAY", type) == 0) { + talloc_free(type); + token->type = SCHEMA_MAY; + + if (*c == '(') { + c++; + n = strcspn(c, ")"); + token->value = talloc_strndup(ctx, c, n); + c += n; + c++; + } else { + token->value = get_def_value(ctx, &c); + } + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("SINGLE-VALUE", type) == 0) { + talloc_free(type); + token->type = SCHEMA_SINGLE_VALUE; + *string = c; + return token; + } + + if (strcasecmp("EQUALITY", type) == 0) { + talloc_free(type); + token->type = SCHEMA_EQUALITY; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("ORDERING", type) == 0) { + talloc_free(type); + token->type = SCHEMA_ORDERING; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("SUBSTR", type) == 0) { + talloc_free(type); + token->type = SCHEMA_SUBSTR; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("SYNTAX", type) == 0) { + talloc_free(type); + token->type = SCHEMA_SYNTAX; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + if (strcasecmp("DESC", type) == 0) { + talloc_free(type); + token->type = SCHEMA_DESC; + + token->value = get_def_value(ctx, &c); + + c = skip_spaces(c); + *string = c; + return token; + } + + token->type = SCHEMA_UNKNOWN; + token->value = type; + if (*c == ')') { + *string = c; + return token; + } + if (*c == '\'') { + c = strchr(++c, '\''); + c++; + } else { + c += strcspn(c, " \t\n"); + } + c = skip_spaces(c); + *string = c; + + return token; +} + +static struct ldb_message *process_entry(TALLOC_CTX *mem_ctx, const char *entry) +{ + TALLOC_CTX *ctx; + struct ldb_message *msg; + struct schema_token *token; + char *c, *s; + int n; + + ctx = talloc_new(mem_ctx); + msg = ldb_msg_new(ctx); + + ldb_msg_add_string(msg, "objectClass", "top"); + + c = talloc_strdup(ctx, entry); + if (!c) return NULL; + + c = skip_spaces(c); + + switch (*c) { + case 'a': + if (strncmp(c, "attributetype", 13) == 0) { + c += 13; + MSG_ADD_STRING("objectClass", "attributeSchema"); + break; + } + goto failed; + case 'o': + if (strncmp(c, "objectclass", 11) == 0) { + c += 11; + MSG_ADD_STRING("objectClass", "classSchema"); + break; + } + goto failed; + default: + goto failed; + } + + c = strchr(c, '('); + if (c == NULL) goto failed; + c++; + + c = skip_spaces(c); + + /* get attributeID */ + n = strcspn(c, " \t"); + s = talloc_strndup(msg, c, n); + MSG_ADD_STRING("attributeID", s); + c += n; + c = skip_spaces(c); + + while (*c != ')') { + token = get_next_schema_token(msg, &c); + if (!token) goto failed; + + switch (token->type) { + case SCHEMA_NAME: + MSG_ADD_STRING("cn", token->value); + MSG_ADD_STRING("name", token->value); + MSG_ADD_STRING("lDAPDisplayName", token->value); + msg->dn = ldb_dn_copy(msg, basedn); + ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Schema,CN=Configuration", token->value); + break; + + case SCHEMA_SUP: + MSG_ADD_M_STRING("subClassOf", token->value); + break; + + case SCHEMA_STRUCTURAL: + MSG_ADD_STRING("objectClassCategory", "1"); + break; + + case SCHEMA_ABSTRACT: + MSG_ADD_STRING("objectClassCategory", "2"); + break; + + case SCHEMA_AUXILIARY: + MSG_ADD_STRING("objectClassCategory", "3"); + break; + + case SCHEMA_MUST: + MSG_ADD_M_STRING("mustContain", token->value); + break; + + case SCHEMA_MAY: + MSG_ADD_M_STRING("mayContain", token->value); + break; + + case SCHEMA_SINGLE_VALUE: + MSG_ADD_STRING("isSingleValued", "TRUE"); + break; + + case SCHEMA_EQUALITY: + /* TODO */ + break; + + case SCHEMA_ORDERING: + /* TODO */ + break; + + case SCHEMA_SUBSTR: + /* TODO */ + break; + + case SCHEMA_SYNTAX: + { + const struct dsdb_syntax *map = + find_syntax_map_by_standard_oid(token->value); + if (!map) { + break; + } + MSG_ADD_STRING("attributeSyntax", map->attributeSyntax_oid); + break; + } + case SCHEMA_DESC: + MSG_ADD_STRING("description", token->value); + break; + + default: + fprintf(stderr, "Unknown Definition: %s\n", token->value); + } + } + + talloc_steal(mem_ctx, msg); + talloc_free(ctx); + return msg; + +failed: + talloc_free(ctx); + return NULL; +} + +static struct schema_conv process_file(FILE *in, FILE *out) +{ + TALLOC_CTX *ctx; + struct schema_conv ret; + char *entry; + int c, t, line; + struct ldb_ldif ldif; + + ldif.changetype = LDB_CHANGETYPE_NONE; + + ctx = talloc_new(NULL); + + ret.count = 0; + ret.failures = 0; + line = 0; + + while ((c = fgetc(in)) != EOF) { + line++; + /* fprintf(stderr, "Parsing line %d\n", line); */ + if (c == '#') { + do { + c = fgetc(in); + } while (c != EOF && c != '\n'); + continue; + } + if (c == '\n') { + continue; + } + + t = 0; + entry = talloc_array(ctx, char, 1024); + if (entry == NULL) exit(-1); + + do { + if (c == '\n') { + entry[t] = '\0'; + if (check_braces(entry) == 0) { + ret.count++; + ldif.msg = process_entry(ctx, entry); + if (ldif.msg == NULL) { + ret.failures++; + fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line); + break; + } + ldb_ldif_write_file(ldb_ctx, out, &ldif); + break; + } + line++; + } else { + entry[t] = c; + t++; + } + if ((t % 1023) == 0) { + entry = talloc_realloc(ctx, entry, char, t + 1024); + if (entry == NULL) exit(-1); + } + } while ((c = fgetc(in)) != EOF); + + if (c != '\n') { + entry[t] = '\0'; + if (check_braces(entry) == 0) { + ret.count++; + ldif.msg = process_entry(ctx, entry); + if (ldif.msg == NULL) { + ret.failures++; + fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line); + break; + } + ldb_ldif_write_file(ldb_ctx, out, &ldif); + } else { + fprintf(stderr, "malformed entry on line %d\n", line); + ret.failures++; + } + } + + if (c == EOF) break; + } + + return ret; +} + +static void usage(void) +{ + printf("Usage: oLschema2ldif -H NONE <options>\n"); + printf("\nConvert OpenLDAP schema to AD-like LDIF format\n\n"); + printf("Options:\n"); + printf(" -I inputfile inputfile of OpenLDAP style schema otherwise STDIN\n"); + printf(" -O outputfile outputfile otherwise STDOUT\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Converts records from an openLdap formatted schema to an ldif schema\n\n"); + exit(1); +} + + int main(int argc, const char **argv) +{ + TALLOC_CTX *ctx; + struct schema_conv ret; + struct ldb_cmdline *options; + FILE *in = stdin; + FILE *out = stdout; + ctx = talloc_new(NULL); + ldb_ctx = ldb_init(ctx, NULL); + + setenv("LDB_URL", "NONE", 1); + options = ldb_cmdline_process(ldb_ctx, argc, argv, usage); + + if (options->basedn == NULL) { + perror("Base DN not specified"); + exit(1); + } else { + basedn = ldb_dn_new(ctx, ldb_ctx, options->basedn); + if ( ! ldb_dn_validate(basedn)) { + perror("Malformed Base DN"); + exit(1); + } + } + + if (options->input) { + in = fopen(options->input, "r"); + if (!in) { + perror(options->input); + exit(1); + } + } + if (options->output) { + out = fopen(options->output, "w"); + if (!out) { + perror(options->output); + exit(1); + } + } + + ret = process_file(in, out); + + fclose(in); + fclose(out); + + printf("Converted %d records with %d failures\n", ret.count, ret.failures); + + return 0; +} diff --git a/source4/utils/setntacl.c b/source4/utils/setntacl.c new file mode 100644 index 0000000000..3a008a4c37 --- /dev/null +++ b/source4/utils/setntacl.c @@ -0,0 +1,28 @@ +/* + Unix SMB/CIFS implementation. + + Set NT ACLs on UNIX files. + + Copyright (C) Tim Potter <tpot@samba.org> 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/>. +*/ + +#include "includes.h" + +int main(int argc, char **argv) +{ + printf("This utility disabled until rewritten\n"); + return 1; +} diff --git a/source4/utils/setnttoken.c b/source4/utils/setnttoken.c new file mode 100644 index 0000000000..3a008a4c37 --- /dev/null +++ b/source4/utils/setnttoken.c @@ -0,0 +1,28 @@ +/* + Unix SMB/CIFS implementation. + + Set NT ACLs on UNIX files. + + Copyright (C) Tim Potter <tpot@samba.org> 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/>. +*/ + +#include "includes.h" + +int main(int argc, char **argv) +{ + printf("This utility disabled until rewritten\n"); + return 1; +} diff --git a/source4/utils/testparm.c b/source4/utils/testparm.c new file mode 100644 index 0000000000..286a4a61fb --- /dev/null +++ b/source4/utils/testparm.c @@ -0,0 +1,256 @@ +/* + Unix SMB/CIFS implementation. + Test validity of smb.conf + Copyright (C) Karl Auer 1993, 1994-1998 + + Extensively modified by Andrew Tridgell, 1995 + Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 2002 + Updated for Samba4 by Andrew Bartlett <abartlet@samba.org> 2006 + + 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/>. +*/ + +/* + * Testbed for loadparm.c/params.c + * + * This module simply loads a specified configuration file and + * if successful, dumps it's contents to stdout. Note that the + * operation is performed with DEBUGLEVEL at 3. + * + * Useful for a quick 'syntax check' of a configuration file. + * + */ + +#include "includes.h" +#include "system/filesys.h" +#include "lib/cmdline/popt_common.h" +#include "lib/socket/socket.h" +#include "param/param.h" + + +/*********************************************** + Here we do a set of 'hard coded' checks for bad + configuration settings. +************************************************/ + +static int do_global_checks(struct loadparm_context *lp_ctx) +{ + int ret = 0; + + if (!directory_exist(lp_lockdir(lp_ctx))) { + fprintf(stderr, "ERROR: lock directory %s does not exist\n", + lp_lockdir(lp_ctx)); + ret = 1; + } + + if (!directory_exist(lp_piddir(lp_ctx))) { + fprintf(stderr, "ERROR: pid directory %s does not exist\n", + lp_piddir(lp_ctx)); + ret = 1; + } + + if (strlen(lp_winbind_separator(lp_ctx)) != 1) { + fprintf(stderr,"ERROR: the 'winbind separator' parameter must be a single character.\n"); + ret = 1; + } + + if (*lp_winbind_separator(lp_ctx) == '+') { + fprintf(stderr,"'winbind separator = +' might cause problems with group membership.\n"); + } + + return ret; +} + + +static int do_share_checks(struct loadparm_context *lp_ctx, const char *cname, const char *caddr, bool silent_mode, + bool show_defaults, const char *section_name, const char *parameter_name) +{ + int ret = 0; + int s; + + for (s=0;s<lp_numservices(lp_ctx);s++) { + struct loadparm_service *service = lp_servicebynum(lp_ctx, s); + if (service != NULL) + if (strlen(lp_servicename(lp_servicebynum(lp_ctx, s))) > 12) { + fprintf(stderr, "WARNING: You have some share names that are longer than 12 characters.\n" ); + fprintf(stderr, "These may not be accessible to some older clients.\n" ); + fprintf(stderr, "(Eg. Windows9x, WindowsMe, and not listed in smbclient in Samba 3.0.)\n" ); + break; + } + } + + for (s=0;s<lp_numservices(lp_ctx);s++) { + struct loadparm_service *service = lp_servicebynum(lp_ctx, s); + if (service != NULL) { + const char **deny_list = lp_hostsdeny(service, lp_default_service(lp_ctx)); + const char **allow_list = lp_hostsallow(service, lp_default_service(lp_ctx)); + int i; + if(deny_list) { + for (i=0; deny_list[i]; i++) { + char *hasstar = strchr_m(deny_list[i], '*'); + char *hasquery = strchr_m(deny_list[i], '?'); + if(hasstar || hasquery) { + fprintf(stderr,"Invalid character %c in hosts deny list (%s) for service %s.\n", + hasstar ? *hasstar : *hasquery, deny_list[i], lp_servicename(service) ); + } + } + } + + if(allow_list) { + for (i=0; allow_list[i]; i++) { + char *hasstar = strchr_m(allow_list[i], '*'); + char *hasquery = strchr_m(allow_list[i], '?'); + if(hasstar || hasquery) { + fprintf(stderr,"Invalid character %c in hosts allow list (%s) for service %s.\n", + hasstar ? *hasstar : *hasquery, allow_list[i], lp_servicename(service) ); + } + } + } + } + } + + + if (!cname) { + if (!silent_mode) { + fprintf(stderr,"Press enter to see a dump of your service definitions\n"); + fflush(stdout); + getc(stdin); + } + if (section_name != NULL || parameter_name != NULL) { + struct loadparm_service *service = NULL; + if (!section_name) { + section_name = GLOBAL_NAME; + service = NULL; + } else if ((!strwicmp(section_name, GLOBAL_NAME)) == 0 && + (service=lp_service(lp_ctx, section_name)) == NULL) { + fprintf(stderr,"Unknown section %s\n", + section_name); + return(1); + } + if (!parameter_name) { + lp_dump_one(stdout, show_defaults, service, lp_default_service(lp_ctx)); + } else { + ret = !lp_dump_a_parameter(lp_ctx, service, parameter_name, stdout); + } + } else { + lp_dump(lp_ctx, stdout, show_defaults, lp_numservices(lp_ctx)); + } + return(ret); + } + + if(cname && caddr){ + /* this is totally ugly, a real `quick' hack */ + for (s=0;s<lp_numservices(lp_ctx);s++) { + struct loadparm_service *service = lp_servicebynum(lp_ctx, s); + if (service != NULL) { + if (allow_access(NULL, lp_hostsdeny(NULL, lp_default_service(lp_ctx)), lp_hostsallow(NULL, lp_default_service(lp_ctx)), cname, caddr) + && allow_access(NULL, lp_hostsdeny(service, lp_default_service(lp_ctx)), lp_hostsallow(service, lp_default_service(lp_ctx)), cname, caddr)) { + fprintf(stderr,"Allow connection from %s (%s) to %s\n", + cname,caddr,lp_servicename(service)); + } else { + fprintf(stderr,"Deny connection from %s (%s) to %s\n", + cname,caddr,lp_servicename(service)); + } + } + } + } + + return ret; +} + + + int main(int argc, const char *argv[]) +{ + static bool silent_mode = false; + int ret = 0; + poptContext pc; +/* + static int show_all_parameters = 0; + static char *new_local_machine = NULL; +*/ + static const char *section_name = NULL; + static char *parameter_name = NULL; + static const char *cname; + static const char *caddr; + static bool show_defaults = false; + struct loadparm_context *lp_ctx; + + struct poptOption long_options[] = { + POPT_AUTOHELP + {"suppress-prompt", 0, POPT_ARG_NONE, &silent_mode, true, "Suppress prompt for enter"}, + {"verbose", 'v', POPT_ARG_NONE, &show_defaults, true, "Show default options too"}, +/* + We need support for smb.conf macros before this will work again + {"server", 'L',POPT_ARG_STRING, &new_local_machine, 0, "Set %%L macro to servername\n"}, +*/ +/* + These are harder to do with the new code structure + {"show-all-parameters", '\0', POPT_ARG_NONE, &show_all_parameters, 1, "Show the parameters, type, possible values" }, +*/ + {"section-name", '\0', POPT_ARG_STRING, §ion_name, 0, "Limit testparm to a named section" }, + {"parameter-name", '\0', POPT_ARG_STRING, ¶meter_name, 0, "Limit testparm to a named parameter" }, + {"client-name", '\0', POPT_ARG_STRING, &cname, 0, "Client DNS name for 'hosts allow' checking (should match reverse lookup)"}, + {"client-ip", '\0', POPT_ARG_STRING, &caddr, 0, "Client IP address for 'hosts allow' checking"}, + POPT_COMMON_SAMBA + POPT_COMMON_VERSION + { NULL } + }; + + setup_logging(NULL, DEBUG_STDERR); + + pc = poptGetContext(NULL, argc, argv, long_options, + POPT_CONTEXT_KEEP_FIRST); + poptSetOtherOptionHelp(pc, "[OPTION...] [host-name] [host-ip]"); + + while(poptGetNextOpt(pc) != -1); + +/* + if (show_all_parameters) { + show_parameter_list(); + exit(0); + } +*/ + + if ( cname && ! caddr ) { + printf ( "ERROR: For 'hosts allow' check you must specify both a DNS name and an IP address.\n" ); + return(1); + } +/* + We need support for smb.conf macros before this will work again + + if (new_local_machine) { + set_local_machine_name(new_local_machine, True); + } +*/ + + lp_ctx = cmdline_lp_ctx; + + /* We need this to force the output */ + lp_set_cmdline(lp_ctx, "log level", "2"); + + fprintf(stderr, "Loaded smb config files from %s\n", lp_configfile(lp_ctx)); + + if (!lp_load(lp_ctx, lp_configfile(lp_ctx))) { + fprintf(stderr,"Error loading services.\n"); + return(1); + } + + fprintf(stderr,"Loaded services file OK.\n"); + + ret = do_global_checks(lp_ctx); + ret |= do_share_checks(lp_ctx, cname, caddr, silent_mode, show_defaults, section_name, parameter_name); + + return(ret); +} + diff --git a/source4/utils/tests/test_net.sh b/source4/utils/tests/test_net.sh new file mode 100755 index 0000000000..3406c87cda --- /dev/null +++ b/source4/utils/tests/test_net.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# Blackbox tests for net + +SERVER=$1 +USERNAME=$2 +PASSWORD=$3 +DOMAIN=$4 +shift 4 + +failed=0 + +samba4bindir=`dirname $0`/../../bin +smbclient=$samba4bindir/smbclient + +testit() { + name="$1" + shift + cmdline="$*" + echo "test: $name" + $cmdline + status=$? + if [ x$status = x0 ]; then + echo "success: $name" + else + echo "failure: $name" + failed=`expr $failed + 1` + fi + return $status +} + +testit "domain join" $VALGRIND bin/net join $DOMAIN $CONFIGURATION -W "$DOMAIN" -U"$USERNAME%$PASSWORD" $@ || failed=`expr $failed + 1` + +testit "Test login with --machine-pass without kerberos" $VALGRIND $smbclient -c 'ls' $CONFIGURATION //$SERVER/tmp --machine-pass -k no || failed=`expr $failed + 1` + +testit "Test login with --machine-pass and kerberos" $VALGRIND $smbclient -c 'ls' $CONFIGURATION //$SERVER/tmp --machine-pass -k yes || failed=`expr $failed + 1` + +exit $failed + + diff --git a/source4/utils/tests/test_nmblookup.sh b/source4/utils/tests/test_nmblookup.sh new file mode 100755 index 0000000000..ad9b3ba799 --- /dev/null +++ b/source4/utils/tests/test_nmblookup.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# Blackbox tests for nmblookup + +NETBIOSNAME=$1 +NETBIOSALIAS=$2 +SERVER=$3 +SERVER_IP=$4 +shift 4 +TORTURE_OPTIONS=$* + +failed=0 + +testit() { + name="$1" + shift + cmdline="$*" + echo "test: $name" + $cmdline + status=$? + if [ x$status = x0 ]; then + echo "success: $name" + else + echo "failure: $name" + failed=`expr $failed + 1` + fi + return $status +} + +testit "nmblookup -U \$SERVER_IP \$SERVER" bin/nmblookup $TORTURE_OPTIONS -U $SERVER_IP $SERVER +testit "nmblookup -U \$SERVER_IP \$NETBIOSNAME" bin/nmblookup $TORTURE_OPTIONS -U $SERVER_IP $NETBIOSNAME +testit "nmblookup -U \$SERVER_IP \$NETBIOSALIAS" bin/nmblookup $TORTURE_OPTIONS -U $SERVER_IP $NETBIOSALIAS +testit "nmblookup \$SERVER" bin/nmblookup $TORTURE_OPTIONS $SERVER +testit "nmblookup \$NETBIOSNAME" bin/nmblookup $TORTURE_OPTIONS $NETBIOSNAME +testit "nmblookup \$NETBIOSALIAS" bin/nmblookup $TORTURE_OPTIONS $NETBIOSALIAS + +exit $failed |