From 0cf550c32aa0018ad834fc2d3cd90d9b2b146621 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 7 Jul 2004 19:18:31 +0000 Subject: [PATCH] r1383: sync from 3.0 tree --- examples/smb.conf.default | 11 +- packaging/RedHat/samba.spec.tmpl | 3 +- source/Makefile.in | 8 +- source/VERSION | 4 +- source/auth/auth_util.c | 55 ++-- source/client/client.c | 24 +- source/client/clitar.c | 6 +- source/client/smbspool.c | 20 +- source/configure.in | 66 ++++- source/include/client.h | 1 + source/include/debug.h | 2 +- source/include/includes.h | 5 + source/include/local.h | 5 + source/include/rpc_dce.h | 3 +- source/include/rpc_netlogon.h | 42 ++- source/include/rpc_samr.h | 15 +- source/include/safe_string.h | 2 +- source/include/smb.h | 65 +++-- source/include/smbldap.h | 3 +- source/lib/afs_settoken.c | 14 +- source/lib/charcnv.c | 2 +- source/lib/iconv.c | 6 +- source/lib/interface.c | 12 +- source/lib/smbldap.c | 25 +- source/lib/snprintf.c | 2 +- source/lib/time.c | 6 + source/lib/username.c | 31 ++- source/lib/util.c | 18 ++ source/lib/util_sock.c | 22 ++ source/lib/util_str.c | 2 +- source/libads/kerberos.c | 4 +- source/libads/kerberos_keytab.c | 554 +++++++++++++++++++++++++++++++++++++ source/libads/kerberos_verify.c | 313 ++++++++++++++------- source/libads/krb5_setpw.c | 49 +++- source/libads/ldap.c | 410 ++++++++++++++++++++++----- source/libads/sasl.c | 4 +- source/libsmb/asn1.c | 12 +- source/libsmb/clientgen.c | 19 +- source/libsmb/clikrb5.c | 29 +- source/libsmb/clispnego.c | 12 +- source/libsmb/conncache.c | 2 - source/libsmb/namequery.c | 391 +++++++++++++------------- source/libsmb/ntlmssp.c | 2 - source/libsmb/smb_signing.c | 46 ++- source/locking/brlock.c | 4 +- source/locking/locking.c | 408 ++++++++++++++++++++++++++- source/nmbd/nmbd_browsesync.c | 5 +- source/nmbd/nmbd_winsserver.c | 7 +- source/nsswitch/winbindd.c | 13 +- source/nsswitch/winbindd_cache.c | 6 + source/nsswitch/winbindd_cm.c | 46 ++- source/nsswitch/winbindd_group.c | 52 +++- source/nsswitch/winbindd_passdb.c | 11 +- source/nsswitch/winbindd_rpc.c | 34 +-- source/nsswitch/winbindd_util.c | 2 +- source/param/loadparm.c | 94 +++++-- source/passdb/login_cache.c | 3 + source/passdb/lookup_sid.c | 11 +- source/passdb/passdb.c | 1 + source/passdb/pdb_ldap.c | 25 +- source/printing/notify.c | 2 +- source/printing/nt_printing.c | 12 +- source/printing/print_cups.c | 47 ++-- source/printing/printing.c | 30 +- source/printing/printing_db.c | 4 +- source/rpc_client/cli_netlogon.c | 11 +- source/rpc_client/cli_pipe.c | 11 +- source/rpc_parse/parse_net.c | 67 ++++- source/rpc_parse/parse_prs.c | 5 +- source/rpc_parse/parse_samr.c | 49 +++- source/rpc_server/srv_lsa_nt.c | 14 +- source/rpc_server/srv_netlog.c | 11 - source/rpc_server/srv_netlog_nt.c | 69 ++++- source/rpc_server/srv_pipe.c | 2 +- source/rpc_server/srv_pipe_hnd.c | 2 +- source/rpc_server/srv_samr_util.c | 6 + source/rpc_server/srv_spoolss_nt.c | 22 +- source/rpc_server/srv_srvsvc_nt.c | 34 ++- source/rpcclient/cmd_spoolss.c | 79 +++++- source/sam/idmap.c | 29 ++ source/sam/idmap_ldap.c | 8 +- source/script/mkproto.awk | 4 +- source/smbd/blocking.c | 2 +- source/smbd/close.c | 34 +++ source/smbd/conn.c | 2 +- source/smbd/connection.c | 8 +- source/smbd/dir.c | 3 +- source/smbd/dosmode.c | 13 + source/smbd/error.c | 11 + source/smbd/filename.c | 27 +- source/smbd/lanman.c | 4 +- source/smbd/mangle_hash.c | 6 +- source/smbd/msdfs.c | 4 +- source/smbd/negprot.c | 19 +- source/smbd/notify_hash.c | 2 +- source/smbd/nttrans.c | 236 ++++++++++++++-- source/smbd/open.c | 375 ++++++++++++++++++++----- source/smbd/oplock.c | 80 +++++- source/smbd/posix_acls.c | 42 +-- source/smbd/process.c | 257 +++++++++++++++-- source/smbd/quotas.c | 204 +++++++++++++- source/smbd/reply.c | 187 +++++++++---- source/smbd/server.c | 10 +- source/smbd/service.c | 41 ++- source/smbd/session.c | 4 +- source/smbd/sesssetup.c | 4 +- source/smbd/trans2.c | 77 +++--- source/smbd/uid.c | 7 + source/smbd/utmp.c | 4 +- source/smbd/vfs.c | 36 ++- source/tdb/Makefile | 5 +- source/torture/torture.c | 4 +- source/torture/vfstest.c | 2 +- source/utils/net_ads.c | 453 +++++++++++++++++++++--------- source/utils/net_rpc.c | 86 +++++- source/utils/ntlm_auth.c | 48 ++-- source/utils/smbcacls.c | 5 - 117 files changed, 4711 insertions(+), 1158 deletions(-) create mode 100644 source/libads/kerberos_keytab.c diff --git a/examples/smb.conf.default b/examples/smb.conf.default index 839fede1233..58d38aa9f7d 100644 --- a/examples/smb.conf.default +++ b/examples/smb.conf.default @@ -4,7 +4,12 @@ # many!) most of which are not shown in this example # # For a step to step guide on installing, configuring and using samba, -# read the Samba HOWTO Collection. +# read the Samba-HOWTO-Collection. This may be obtained from: +# http://www.samba.org/samba/docs/Samba-HOWTO-Collection.pdf +# +# Many working examples of smb.conf files can be found in the +# Samba-Guide which is generated daily and can be downloaded from: +# http://www.samba.org/samba/docs/Samba-Guide.pdf # # Any line which starts with a ; (semi-colon) or a # (hash) # is a comment and is ignored. In this example we will use a # @@ -17,7 +22,7 @@ #======================= Global Settings ===================================== [global] -# workgroup = NT-Domain-Name or Workgroup-Name, eg: REDHAT4 +# workgroup = NT-Domain-Name or Workgroup-Name, eg: MIDEARTH workgroup = MYGROUP # server string is the equivalent of the NT Description field @@ -25,7 +30,7 @@ # Security mode. Defines in which mode Samba will operate. Possible # values are share, user, server, domain and ads. Most people will want -# user level security. See the HOWTO Collection for details. +# user level security. See the Samba-HOWTO-Collection for details. security = user # This option is important for security. It allows you to restrict diff --git a/packaging/RedHat/samba.spec.tmpl b/packaging/RedHat/samba.spec.tmpl index 06237af7260..aafb9bd2188 100644 --- a/packaging/RedHat/samba.spec.tmpl +++ b/packaging/RedHat/samba.spec.tmpl @@ -16,7 +16,8 @@ Source998: filter-requires-samba_rh8.sh Source999: filter-requires-samba_rh9.sh Packager: Gerald Carter [Samba-Team] -Requires: pam pam-devel kernel glibc +Requires: pam openldap krb5-libs +BuildRequires: openldap-devel krb5-devel pam-devel Prereq: chkconfig fileutils /sbin/ldconfig Provides: samba = %{version} Obsoletes: samba-common, samba-client, samba-swat diff --git a/source/Makefile.in b/source/Makefile.in index c8d2b959a4d..398ad4e0e3f 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -228,7 +228,7 @@ KRBCLIENT_OBJ = libads/kerberos.o libads/ads_status.o LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o libads/sasl.o \ libads/krb5_setpw.o libads/ldap_user.o \ - libads/ads_struct.o \ + libads/ads_struct.o libads/kerberos_keytab.o \ libads/disp_sec.o libads/ads_utils.o libads/ldap_utils.o \ libads/ads_ldap.o libads/authdata.o @@ -1315,9 +1315,9 @@ installswat: installdirs installmsg @$(SHELL) $(srcdir)/script/installswat.sh $(DESTDIR)$(SWATDIR) $(srcdir) installclientlib: installdirs libsmbclient - @$(SHELL) $(srcdir)/script/installdirs.sh $(DESTDIR)${prefix}/lib - -$(INSTALLCLIENTCMD_SH) bin/libsmbclient.@SHLIBEXT@ $(DESTDIR)${prefix}/lib - -$(INSTALLCLIENTCMD_A) bin/libsmbclient.a $(DESTDIR)${prefix}/lib + @$(SHELL) $(srcdir)/script/installdirs.sh $(DESTDIR)$(LIBDIR) + -$(INSTALLCLIENTCMD_SH) bin/libsmbclient.@SHLIBEXT@ $(DESTDIR)$(LIBDIR) + -$(INSTALLCLIENTCMD_A) bin/libsmbclient.a $(DESTDIR)$(LIBDIR) @$(SHELL) $(srcdir)/script/installdirs.sh $(DESTDIR)${prefix}/include -$(INSTALLCMD) $(srcdir)/include/libsmbclient.h $(DESTDIR)${prefix}/include diff --git a/source/VERSION b/source/VERSION index e493805fdb4..5a7d9836c85 100644 --- a/source/VERSION +++ b/source/VERSION @@ -29,7 +29,7 @@ SAMBA_VERSION_RELEASE=5 # e.g. SAMBA_VERSION_PRE_RELEASE=1 # # -> "2.2.9pre1" # ######################################################## -SAMBA_VERSION_PRE_RELEASE=1 +SAMBA_VERSION_PRE_RELEASE=2 ######################################################## # For 'rc' releases the version will be # @@ -51,7 +51,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_SVN_SNAPSHOT= +SAMBA_VERSION_IS_SVN_SNAPSHOT=yes ######################################################## # This can be set by vendors if they want... # diff --git a/source/auth/auth_util.c b/source/auth/auth_util.c index 9a03e7fe13c..5e8f18881fb 100644 --- a/source/auth/auth_util.c +++ b/source/auth/auth_util.c @@ -972,25 +972,25 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create ) { struct passwd *pw = NULL; char *p; - fstring mapped_username; - fstring strip_username; + fstring username; /* we only save a copy of the username it has been mangled by winbindd use default domain */ save_username[0] = '\0'; - - /* save a local copy of the username and run it through the - username map */ - fstrcpy( mapped_username, domuser ); - map_username( mapped_username ); + /* don't call map_username() here since it has to be done higher + up the stack so we don't call it mutliple times */ + + fstrcpy( username, domuser ); - p = strchr_m( mapped_username, *lp_winbind_separator() ); + p = strchr_m( username, *lp_winbind_separator() ); /* code for a DOMAIN\user string */ if ( p ) { + fstring strip_username; + pw = Get_Pwnam( domuser ); if ( pw ) { /* make sure we get the case of the username correct */ @@ -999,8 +999,10 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create ) if ( !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) { char *domain; - domain = mapped_username; + /* split the domain and username into 2 strings */ *p = '\0'; + domain = username; + fstr_sprintf(save_username, "%s%c%s", domain, *lp_winbind_separator(), pw->pw_name); } else @@ -1011,26 +1013,26 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create ) } /* setup for lookup of just the username */ - /* remember that p and mapped_username are overlapping memory */ + /* remember that p and username are overlapping memory */ p++; fstrcpy( strip_username, p ); - fstrcpy( mapped_username, strip_username ); + fstrcpy( username, strip_username ); } /* just lookup a plain username */ - pw = Get_Pwnam(mapped_username); + pw = Get_Pwnam(username); /* Create local user if requested. */ if ( !pw && create ) { /* Don't add a machine account. */ - if (mapped_username[strlen(mapped_username)-1] == '$') + if (username[strlen(username)-1] == '$') return NULL; - auth_add_user_script(NULL, mapped_username); - pw = Get_Pwnam(mapped_username); + auth_add_user_script(NULL, username); + pw = Get_Pwnam(username); } /* one last check for a valid passwd struct */ @@ -1207,7 +1209,7 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, /* Create a 'combined' list of all SIDs we might want in the SD */ - all_group_SIDs = malloc(sizeof(DOM_SID) * (info3->num_groups2 +info3->num_other_sids)); + all_group_SIDs = malloc(sizeof(DOM_SID) * (info3->num_groups2 + info3->num_other_sids + n_lgroupSIDs)); if (!all_group_SIDs) { DEBUG(0, ("malloc() failed for DOM_SID list!\n")); @@ -1216,12 +1218,6 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } -#if 0 /* JERRY -- no such thing as local groups in current code */ - /* Copy the 'local' sids */ - memcpy(all_group_SIDs, lgroupSIDs, sizeof(DOM_SID) * n_lgroupSIDs); - SAFE_FREE(lgroupSIDs); -#endif - /* and create (by appending rids) the 'domain' sids */ for (i = 0; i < info3->num_groups2; i++) { @@ -1254,13 +1250,22 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, sid_copy(&all_group_SIDs[info3->num_groups2 + i], &info3->other_sids[i].sid); } + + + /* add local alias sids */ + + for (i = 0; i < n_lgroupSIDs; i++) { + sid_copy(&all_group_SIDs[info3->num_groups2 + + info3->num_other_sids + i], + &lgroupSIDs[i]); + } /* Where are the 'global' sids... */ /* can the user be guest? if yes, where is it stored? */ nt_status = create_nt_user_token(&user_sid, &group_sid, - info3->num_groups2 + info3->num_other_sids, + info3->num_groups2 + info3->num_other_sids + n_lgroupSIDs, all_group_SIDs, False, &token); if ( !NT_STATUS_IS_OK(nt_status) ) { @@ -1425,8 +1430,10 @@ BOOL is_trusted_domain(const char* dom_name) /* if we are a DC, then check for a direct trust relationships */ - if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) { + if ( IS_DC ) { become_root(); + DEBUG (5,("is_trusted_domain: Checking for domain trust with [%s]\n", + dom_name )); ret = secrets_fetch_trusted_domain_password(dom_name, &pass, &trustdom_sid, &lct); unbecome_root(); SAFE_FREE(pass); diff --git a/source/client/client.c b/source/client/client.c index a0470315f82..1fccfaa581c 100644 --- a/source/client/client.c +++ b/source/client/client.c @@ -1571,7 +1571,7 @@ static int cmd_open(void) } pstrcat(mask,buf); - cli_open(cli, mask, O_RDWR, DENY_ALL); + cli_nt_create(cli, mask, FILE_READ_DATA); return 0; } @@ -1869,6 +1869,21 @@ static int cmd_lowercase(void) } /**************************************************************************** + Toggle the case sensitive flag. +****************************************************************************/ + +static int cmd_setcase(void) +{ + BOOL orig_case_sensitive = cli_set_case_sensitive(cli, False); + + cli_set_case_sensitive(cli, !orig_case_sensitive); + DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ? + "on":"off")); + + return 0; +} + +/**************************************************************************** Toggle the recurse flag. ****************************************************************************/ @@ -2179,6 +2194,7 @@ static struct {"archive",cmd_archive,"\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}}, {"blocksize",cmd_block,"blocksize (default 20)",{COMPL_NONE,COMPL_NONE}}, {"cancel",cmd_cancel," cancel a print queue entry",{COMPL_NONE,COMPL_NONE}}, + {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}}, {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}}, {"chmod",cmd_chmod," chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}}, {"chown",cmd_chown," chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}}, @@ -2563,9 +2579,10 @@ static void readline_callback(void) Process commands on stdin. ****************************************************************************/ -static void process_stdin(void) +static int process_stdin(void) { const char *ptr; + int rc = 0; while (1) { pstring tok; @@ -2593,13 +2610,14 @@ static void process_stdin(void) if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue; if ((i = process_tok(tok)) >= 0) { - commands[i].fn(); + rc = commands[i].fn(); } else if (i == -2) { d_printf("%s: command abbreviation ambiguous\n",tok); } else { d_printf("%s: command not found\n",tok); } } + return rc; } /***************************************************** diff --git a/source/client/clitar.c b/source/client/clitar.c index e43b3e4cc50..64c194b54da 100644 --- a/source/client/clitar.c +++ b/source/client/clitar.c @@ -1357,9 +1357,8 @@ int cmd_tar(void) if (!tar_parseargs(argcl, argl, buf, 0)) return 1; - process_tar(); SAFE_FREE(argl); - return 0; + return process_tar(); } /**************************************************************************** @@ -1368,6 +1367,7 @@ Command line (option) version int process_tar(void) { + int rc = 0; initarbuf(); switch(tar_type) { case 'x': @@ -1445,7 +1445,7 @@ int process_tar(void) clipn = 0; must_free_cliplist = False; } - return(0); + return rc; } /**************************************************************************** diff --git a/source/client/smbspool.c b/source/client/smbspool.c index 5daefec5a55..a67ccadb90b 100644 --- a/source/client/smbspool.c +++ b/source/client/smbspool.c @@ -36,7 +36,7 @@ extern BOOL in_client; /* Boolean for client library */ */ static void list_devices(void); -static struct cli_state *smb_connect(const char *, const char *, const char *, const char *, const char *); +static struct cli_state *smb_connect(const char *, const char *, int, const char *, const char *, const char *); static int smb_print(struct cli_state *, char *, FILE *); @@ -50,6 +50,7 @@ static int smb_print(struct cli_state *, char *, FILE *); { int i; /* Looping var */ int copies; /* Number of copies */ + int port; /* Port number */ char uri[1024], /* URI */ *sep, /* Pointer to separator */ *password; /* Password */ @@ -87,7 +88,7 @@ static int smb_print(struct cli_state *, char *, FILE *); fputs(" The DEVICE_URI environment variable can also contain the\n", stderr); fputs(" destination printer:\n", stderr); fputs("\n", stderr); - fputs(" smb://[username:password@][workgroup/]server/printer\n", stderr); + fputs(" smb://[username:password@][workgroup/]server[:port]/printer\n", stderr); return (1); } @@ -179,7 +180,17 @@ static int smb_print(struct cli_state *, char *, FILE *); } else workgroup = NULL; + + if ((sep = strrchr_m(server, ':')) != NULL) + { + *sep++ = '\0'; + port=atoi(sep); + } + else + port=0; + + /* * Setup the SAMBA server state... */ @@ -201,7 +212,7 @@ static int smb_print(struct cli_state *, char *, FILE *); do { - if ((cli = smb_connect(workgroup, server, printer, username, password)) == NULL) + if ((cli = smb_connect(workgroup, server, port, printer, username, password)) == NULL) { if (getenv("CLASS") == NULL) { @@ -267,6 +278,7 @@ list_devices(void) static struct cli_state * /* O - SMB connection */ smb_connect(const char *workgroup, /* I - Workgroup */ const char *server, /* I - Server */ + const int port, /* I - Port */ const char *share, /* I - Printer */ const char *username, /* I - Username */ const char *password) /* I - Password */ @@ -281,7 +293,7 @@ smb_connect(const char *workgroup, /* I - Workgroup */ get_myname(myname); - nt_status = cli_full_connection(&c, myname, server, NULL, 0, share, "?????", + nt_status = cli_full_connection(&c, myname, server, NULL, port, share, "?????", username, workgroup, password, 0, Undefined, NULL); if (!NT_STATUS_IS_OK(nt_status)) { diff --git a/source/configure.in b/source/configure.in index e1fc69b4b79..e57076a346a 100644 --- a/source/configure.in +++ b/source/configure.in @@ -11,6 +11,11 @@ AC_ENABLE_SHARED SMB_VERSION_STRING=`cat include/version.h | grep 'SAMBA_VERSION_OFFICIAL_STRING' | cut -d '"' -f2` echo "SAMBA VERSION: ${SMB_VERSION_STRING}" +SAMBA_VERSION_SVN_REVISION=`cat include/version.h | grep 'SAMBA_VERSION_SVN_REVISION' | cut -d ' ' -f3-` +if test -n "${SAMBA_VERSION_SVN_REVISION}";then + echo "BUILD REVISION: ${SAMBA_VERSION_SVN_REVISION}" +fi + ################################################# # Directory handling stuff to support both the # legacy SAMBA directories and FHS compliant @@ -707,10 +712,12 @@ if test x$enable_cups != xno; then AC_PATH_PROG(CUPS_CONFIG, cups-config) if test "x$CUPS_CONFIG" != x; then - AC_DEFINE(HAVE_CUPS,1,[Whether we have CUPS]) + AC_DEFINE(HAVE_CUPS,1,[Whether we have CUPS]) CFLAGS="$CFLAGS `$CUPS_CONFIG --cflags`" LDFLAGS="$LDFLAGS `$CUPS_CONFIG --ldflags`" PRINT_LIBS="$PRINT_LIBS `$CUPS_CONFIG --libs`" + elif test x$enable_cups == xyes; then + AC_MSG_ERROR(Cups support required but cups-config not located. Make sure cups-devel related files are installed.) fi fi @@ -2708,6 +2715,7 @@ if test x"$with_ads_support" != x"no"; then # now see if we can find the krb5 libs in standard paths # or as specified above AC_CHECK_LIB_EXT(krb5, KRB5_LIBS, krb5_mk_req_extended) + AC_CHECK_LIB_EXT(krb5, KRB5_LIBS, krb5_kt_compare) ######################################################## # now see if we can find the gssapi libs in standard paths @@ -2730,6 +2738,9 @@ if test x"$with_ads_support" != x"no"; then AC_CHECK_FUNC_EXT(krb5_free_ktypes, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_free_data_contents, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_principal_get_comp_string, $KRB5_LIBS) + AC_CHECK_FUNC_EXT(krb5_free_unparsed_name, $KRB5_LIBS) + AC_CHECK_FUNC_EXT(krb5_free_keytab_entry_contents, $KRB5_LIBS) + AC_CHECK_FUNC_EXT(krb5_kt_free_entry, $KRB5_LIBS) LIBS="$LIBS $KRB5_LIBS" @@ -2812,6 +2823,18 @@ if test x"$with_ads_support" != x"no"; then [Whether the AP_OPTS_USE_SUBKEY ap option is available]) fi + AC_CACHE_CHECK([for KV5M_KEYTAB], + samba_cv_HAVE_KV5M_KEYTAB,[ + AC_TRY_COMPILE([#include ], + [krb5_keytab_entry entry; entry.magic = KV5M_KEYTAB;], + samba_cv_HAVE_KV5M_KEYTAB=yes, + samba_cv_HAVE_KV5M_KEYTAB=no)]) + + if test x"$samba_cv_HAVE_KV5M_KEYTAB" = x"yes"; then + AC_DEFINE(HAVE_KV5M_KEYTAB,1, + [Whether the KV5M_KEYTAB option is available]) + fi + AC_CACHE_CHECK([for the krb5_princ_component macro], samba_cv_HAVE_KRB5_PRINC_COMPONENT,[ AC_TRY_LINK([#include ], @@ -2862,7 +2885,45 @@ if test x"$with_ads_support" != x"no"; then KRB5_LIBS="" with_ads_support=no fi - LIBS="$ac_save_LIBS" + + AC_CACHE_CHECK([for WRFILE: keytab support], + samba_cv_HAVE_WRFILE_KEYTAB,[ + AC_TRY_RUN([ +#include + main() + { + krb5_context context; + krb5_keytab keytab; + + krb5_init_context(&context); + if (krb5_kt_resolve(context, "WRFILE:api", &keytab)) + exit(0); + exit(1); + }], + samba_cv_HAVE_WRFILE_KEYTAB=no, + samba_cv_HAVE_WRFILE_KEYTAB=yes)]) + + if test x"$samba_cv_HAVE_WRFILE_KEYTAB" = x"yes"; then + AC_DEFINE(HAVE_WRFILE_KEYTAB,1, + [Whether the WRFILE:-keytab is supported]) + fi + + AC_CACHE_CHECK([for krb5_princ_realm returns krb5_realm or krb5_data], + samba_cv_KRB5_PRINC_REALM_RETURNS_REALM,[ + AC_TRY_COMPILE([#include ], + [ + krb5_context context; + krb5_principal principal; + krb5_realm realm; realm = *krb5_princ_realm(context, principal);], + samba_cv_KRB5_PRINC_REALM_RETURNS_REALM=yes, + samba_cv_KRB5_PRINC_REALM_RETURNS_REALM=no)]) + + if test x"$samba_cv_KRB5_PRINC_REALM_RETURNS_REALM" = x"yes"; then + AC_DEFINE(KRB5_PRINC_REALM_RETURNS_REALM,1, + [Whether krb5_princ_realm returns krb5_realm or krb5_data]) + fi + +LIBS="$ac_save_LIBS" fi ######################################################## @@ -2950,6 +3011,7 @@ AC_ARG_WITH(smbmount, ) + ################################################# # check for a PAM clear-text auth, accounts, password and session support with_pam_for_crypt=no diff --git a/source/include/client.h b/source/include/client.h index 968b73f0b41..52a6c76299d 100644 --- a/source/include/client.h +++ b/source/include/client.h @@ -153,6 +153,7 @@ struct cli_state { BOOL (*oplock_handler)(struct cli_state *cli, int fnum, unsigned char level); BOOL force_dos_errors; + BOOL case_sensitive; /* False by default. */ /* was this structure allocated by cli_initialise? If so, then free in cli_shutdown() */ diff --git a/source/include/debug.h b/source/include/debug.h index 52e06b9360b..05a9a3f0c52 100644 --- a/source/include/debug.h +++ b/source/include/debug.h @@ -33,7 +33,7 @@ * diffferent prototype declarations), so we must do these by hand. */ /* I know the __attribute__ stuff is ugly, but it does ensure we get the - arguemnts to DEBUG() right. We have got them wrong too often in the + arguments to DEBUG() right. We have got them wrong too often in the past. The PRINTFLIKE comment does the equivalent for SGI MIPSPro. */ diff --git a/source/include/includes.h b/source/include/includes.h index ea8eb1a3043..7657984bfb1 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -1239,6 +1239,7 @@ int asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3); #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) #define snprintf smb_snprintf +#define vsnprintf smb_vsnprintf #endif void sys_adminlog(int priority, const char *format_str, ...) PRINTF_ATTRIBUTE(2,3); @@ -1293,6 +1294,10 @@ krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock); #endif +#ifndef HAVE_KRB5_FREE_UNPARSED_NAME +void krb5_free_unparsed_name(krb5_context ctx, char *val); +#endif + /* Samba wrapper function for krb5 functionality. */ void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr); int create_kerberos_key_from_string(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype); diff --git a/source/include/local.h b/source/include/local.h index 540365047a2..7ac2e256120 100644 --- a/source/include/local.h +++ b/source/include/local.h @@ -230,4 +230,9 @@ /* size of listen() backlog in smbd */ #define SMBD_LISTEN_BACKLOG 50 +/* Number of microseconds to wait before a sharing violation. */ +#define SHARING_VIOLATION_USEC_WAIT 950000 + +#define MAX_LDAP_REPLICATION_SLEEP_TIME 5000 /* In milliseconds. */ + #endif diff --git a/source/include/rpc_dce.h b/source/include/rpc_dce.h index 0df903109db..57b1184bd96 100644 --- a/source/include/rpc_dce.h +++ b/source/include/rpc_dce.h @@ -71,7 +71,8 @@ enum RPC_PKT_TYPE to NT4. Actually, anything other than 1ff would seem to do... */ #define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff -#define NETLOGON_NEG_SCHANNEL 0x40000000 +#define NETLOGON_NEG_SCHANNEL 0x40000000 +#define NETLOGON_NEG_DOMAIN_TRUST_ACCOUNT 0x2010b000 enum netsec_direction { diff --git a/source/include/rpc_netlogon.h b/source/include/rpc_netlogon.h index a5b93b0238a..44beb2b8c82 100644 --- a/source/include/rpc_netlogon.h +++ b/source/include/rpc_netlogon.h @@ -68,6 +68,11 @@ #define SAM_DATABASE_BUILTIN 0x01 /* BUILTIN users and groups */ #define SAM_DATABASE_PRIVS 0x02 /* Privileges */ +#define NETLOGON_CONTROL_REDISCOVER 0x5 +#define NETLOGON_CONTROL_TC_QUERY 0x6 +#define NETLOGON_CONTROL_TRANSPORT_NOTIFY 0x7 +#define NETLOGON_CONTROL_SET_DBFLAG 0xfffe + #if 0 /* I think this is correct - it's what gets parsed on the wire. JRA. */ /* NET_USER_INFO_2 */ @@ -204,7 +209,7 @@ typedef struct netlogon_2_info uint32 flags; /* 0x0 - undocumented */ uint32 pdc_status; /* 0x0 - undocumented */ uint32 ptr_trusted_dc_name; /* pointer to trusted domain controller name */ - uint32 tc_status; /* 0x051f - ERROR_NO_LOGON_SERVERS */ + uint32 tc_status; UNISTR2 uni_trusted_dc_name; /* unicode string - trusted dc name */ } NETLOGON_INFO_2; @@ -255,6 +260,26 @@ typedef struct net_r_logon_ctrl_info NTSTATUS status; } NET_R_LOGON_CTRL; + +typedef struct ctrl_data_info_5 +{ + uint32 function_code; + + uint32 ptr_domain; + UNISTR2 domain; + +} CTRL_DATA_INFO_5; + +typedef struct ctrl_data_info_6 +{ + uint32 function_code; + + uint32 ptr_domain; + UNISTR2 domain; + +} CTRL_DATA_INFO_6; + + /******************************************************** Logon Control2 Query @@ -266,13 +291,16 @@ typedef struct net_r_logon_ctrl_info /* NET_Q_LOGON_CTRL2 - LSA Netr Logon Control 2 */ typedef struct net_q_logon_ctrl2_info { - uint32 ptr; /* undocumented buffer pointer */ - UNISTR2 uni_server_name; /* server name, starting with two '\'s */ + uint32 ptr; /* undocumented buffer pointer */ + UNISTR2 uni_server_name; /* server name, starting with two '\'s */ + + uint32 function_code; + uint32 query_level; + union { + CTRL_DATA_INFO_5 info5; + CTRL_DATA_INFO_6 info6; + } info; - uint32 function_code; /* 0x1 */ - uint32 query_level; /* 0x1, 0x3 */ - uint32 switch_value; /* 0x1 */ - } NET_Q_LOGON_CTRL2; /******************************************************* diff --git a/source/include/rpc_samr.h b/source/include/rpc_samr.h index 089941de3aa..ae603c9cd93 100644 --- a/source/include/rpc_samr.h +++ b/source/include/rpc_samr.h @@ -1068,6 +1068,14 @@ typedef struct samr_group_info1 } GROUP_INFO1; +typedef struct samr_group_info2 +{ + uint16 level; + UNIHDR hdr_acct_name; + UNISTR2 uni_acct_name; + +} GROUP_INFO2; + typedef struct samr_group_info3 { uint32 unknown_1; /* 0x0000 0003 - number of group members? */ @@ -1090,6 +1098,7 @@ typedef struct group_info_ctr union { GROUP_INFO1 info1; + GROUP_INFO2 info2; GROUP_INFO3 info3; GROUP_INFO4 info4; @@ -1734,11 +1743,7 @@ typedef struct q_samr_get_dom_pwinfo typedef struct r_samr_get_dom_pwinfo { /* - * Previously this was 3 uint16's. However, after some tests - * it appears that the data len for the signing needs to be 16. - * Not sure how 3 unit16's ever worked since the length always - * turned out to 12. 3 uint32's + NT_STATUS == 16 bytes. Tested - * using NT and 2k. --jerry + * See Samba4 IDL */ uint16 unk_0; uint32 unk_1; diff --git a/source/include/safe_string.h b/source/include/safe_string.h index b22c5efcc99..d278e29aca5 100644 --- a/source/include/safe_string.h +++ b/source/include/safe_string.h @@ -59,7 +59,7 @@ #ifdef strncasecmp #undef strncasecmp #endif -#define strncasecmp __ERROR__XX__NEVER_USE_STRCASECMP__; +#define strncasecmp __ERROR__XX__NEVER_USE_STRNCASECMP__; #endif /* !_SPLINT_ */ diff --git a/source/include/smb.h b/source/include/smb.h index 54a69d1433a..a802e962266 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -584,6 +584,24 @@ struct interface struct in_addr nmask; }; +/* struct used by share mode violation error processing */ +typedef struct { + pid_t pid; + uint16 mid; + struct timeval time; + SMB_DEV_T dev; + SMB_INO_T inode; + uint16 port; +} deferred_open_entry; + +/* Internal message queue for deferred opens. */ +struct pending_message_list { + struct pending_message_list *next, *prev; + struct timeval msg_time; /* The timeout time */ + DATA_BLOB buf; + DATA_BLOB private_data; +}; + /* struct returned by get_share_modes */ typedef struct { pid_t pid; @@ -663,28 +681,14 @@ struct locking_key { SMB_INO_T inode; }; -struct locking_data { - union { - int num_share_mode_entries; - share_mode_entry dummy; /* Needed for alignment. */ - } u; - /* the following two entries are implicit - share_mode_entry modes[num_share_mode_entries]; - char file_name[]; - */ -}; - - /* the following are used by loadparm for option lists */ -typedef enum -{ - P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST, - P_STRING,P_USTRING,P_GSTRING,P_UGSTRING,P_ENUM,P_SEP +typedef enum { + P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST, + P_STRING,P_USTRING,P_GSTRING,P_UGSTRING,P_ENUM,P_SEP } parm_type; -typedef enum -{ - P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE +typedef enum { + P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE } parm_class; /* passed to br lock code */ @@ -1345,7 +1349,8 @@ enum ldap_ssl_types {LDAP_SSL_ON, LDAP_SSL_OFF, LDAP_SSL_START_TLS}; enum ldap_passwd_sync_types {LDAP_PASSWD_SYNC_ON, LDAP_PASSWD_SYNC_OFF, LDAP_PASSWD_SYNC_ONLY}; /* Remote architectures we know about. */ -enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, RA_WIN2K, RA_WINXP, RA_WIN2K3, RA_SAMBA}; +enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, + RA_WIN2K, RA_WINXP, RA_WIN2K3, RA_SAMBA, RA_CIFSFS}; /* case handling */ enum case_handling {CASE_LOWER,CASE_UPPER}; @@ -1410,6 +1415,7 @@ extern int chain_size; #define EXCLUSIVE_OPLOCK 1 #define BATCH_OPLOCK 2 #define LEVEL_II_OPLOCK 4 +#define INTERNAL_OPEN_ONLY 8 #define EXCLUSIVE_OPLOCK_TYPE(lck) ((lck) & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) #define BATCH_OPLOCK_TYPE(lck) ((lck) & BATCH_OPLOCK) @@ -1461,6 +1467,25 @@ extern int chain_size; #define LEVEL_II_OPLOCK_BREAK_CMD 0x3 #define ASYNC_LEVEL_II_OPLOCK_BREAK_CMD 0x4 +/* Add the "deferred open" message. */ +#define RETRY_DEFERRED_OPEN_CMD 0x5 + +/* + * And the message format for it. Keep the same message length. + * + * 0 2 2+pid 2+pid+dev 2+pid+dev+ino + * +----+--------+-------+--------+---------+ + * | cmd| pid | dev | inode | mid | + * +----+--------+-------+--------+---------+ + */ + +#define DEFERRED_OPEN_CMD_OFFSET 0 +#define DEFERRED_OPEN_PID_OFFSET 2 /* pid we're *sending* from. */ +#define DEFERRED_OPEN_DEV_OFFSET (DEFERRED_OPEN_PID_OFFSET + sizeof(pid_t)) +#define DEFERRED_OPEN_INODE_OFFSET (DEFERRED_OPEN_DEV_OFFSET + sizeof(SMB_DEV_T)) +#define DEFERRED_OPEN_MID_OFFSET (DEFERRED_OPEN_INODE_OFFSET + sizeof(SMB_INO_T)) +#define DEFERRED_OPEN_MSG_LEN OPLOCK_BREAK_MSG_LEN + /* * Capabilities abstracted for different systems. */ diff --git a/source/include/smbldap.h b/source/include/smbldap.h index 61b8df0f0ef..c7de7d84b37 100644 --- a/source/include/smbldap.h +++ b/source/include/smbldap.h @@ -153,5 +153,6 @@ struct smbldap_state { struct smbldap_state; -#endif /* _SMBLDAP_H */ +#define LDAP_CONNECT_DEFAULT_TIMEOUT 5 +#endif /* _SMBLDAP_H */ diff --git a/source/lib/afs_settoken.c b/source/lib/afs_settoken.c index eb10c4c66d4..5c646c72e48 100644 --- a/source/lib/afs_settoken.c +++ b/source/lib/afs_settoken.c @@ -28,12 +28,16 @@ #include #include #include +#include -_syscall5(int, afs_syscall, int, subcall, - char *, path, - int, cmd, - char *, cmarg, - int, follow); +int afs_syscall( int subcall, + char * path, + int cmd, + char * cmarg, + int follow) +{ + return( syscall( SYS_afs_syscall, subcall, path, cmd, cmarg, follow)); +} struct ClearToken { uint32 AuthHandle; diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c index b9791931a35..3d7678c34cb 100644 --- a/source/lib/charcnv.c +++ b/source/lib/charcnv.c @@ -932,7 +932,7 @@ size_t pull_ascii_fstring(char *dest, const void *src) size_t pull_ascii_nstring(char *dest, size_t dest_len, const void *src) { - return pull_ascii(dest, src, dest_len, sizeof(nstring), STR_TERMINATE); + return pull_ascii(dest, src, dest_len, sizeof(nstring)-1, STR_TERMINATE); } /** diff --git a/source/lib/iconv.c b/source/lib/iconv.c index 7df73192f24..4c9ecf992e6 100644 --- a/source/lib/iconv.c +++ b/source/lib/iconv.c @@ -129,7 +129,11 @@ static size_t sys_iconv(void *cd, size_t ret = iconv((iconv_t)cd, inbuf, inbytesleft, outbuf, outbytesleft); - if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL); + if (ret == (size_t)-1) { + int saved_errno = errno; + iconv(cd, NULL, NULL, NULL, NULL); + errno = saved_errno; + } return ret; #else errno = EINVAL; diff --git a/source/lib/interface.c b/source/lib/interface.c index 4d8010e31bc..adf9ca34381 100644 --- a/source/lib/interface.c +++ b/source/lib/interface.c @@ -94,7 +94,7 @@ This handles the following different forms: 4) ip/mask 5) bcast/mask ****************************************************************************/ -static void interpret_interface(const char *token) +static void interpret_interface(char *token) { struct in_addr ip, nmask; char *p; @@ -130,9 +130,9 @@ static void interpret_interface(const char *token) } /* parse it into an IP address/netmasklength pair */ - *p++ = 0; - + *p = 0; ip = *interpret_addr2(token); + *p++ = '/'; if (strlen(p) > 2) { nmask = *interpret_addr2(p); @@ -207,7 +207,11 @@ void load_interfaces(void) if (ptr) { while (*ptr) { - interpret_interface(*ptr); + char *ptr_cpy = strdup(*ptr); + if (ptr_cpy) { + interpret_interface(ptr_cpy); + free(ptr_cpy); + } ptr++; } } diff --git a/source/lib/smbldap.c b/source/lib/smbldap.c index 21e2a7c1018..d058613f004 100644 --- a/source/lib/smbldap.c +++ b/source/lib/smbldap.c @@ -676,7 +676,7 @@ static int rebindproc_with_state (LDAP * ld, char **whop, char **credp, *methodp = LDAP_AUTH_SIMPLE; } - gettimeofday(&(ldap_state->last_rebind),NULL); + GetTimeOfDay(&ldap_state->last_rebind); return 0; } @@ -704,7 +704,7 @@ static int rebindproc_connect_with_state (LDAP *ldap_struct, rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret); - gettimeofday(&(ldap_state->last_rebind),NULL); + GetTimeOfDay(&ldap_state->last_rebind); return rc; } @@ -755,8 +755,7 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_ char *ldap_secret; /* get the password */ - if (!fetch_ldap_pw(&ldap_dn, &ldap_secret)) - { + if (!fetch_ldap_pw(&ldap_dn, &ldap_secret)) { DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n")); return LDAP_INVALID_CREDENTIALS; } @@ -808,7 +807,7 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_ } /********************************************************************** -Connect to LDAP server (called before every ldap operation) + Connect to LDAP server (called before every ldap operation) *********************************************************************/ static int smbldap_open(struct smbldap_state *ldap_state) { @@ -854,7 +853,7 @@ static int smbldap_open(struct smbldap_state *ldap_state) ldap_state->last_ping = time(NULL); - DEBUG(4,("The LDAP server is succesful connected\n")); + DEBUG(4,("The LDAP server is succesfully connected\n")); return LDAP_SUCCESS; } @@ -933,25 +932,25 @@ int smbldap_search(struct smbldap_state *ldap_state, if (ldap_state->last_rebind.tv_sec > 0) { struct timeval tval; - int tdiff = 0; + SMB_BIG_INT tdiff = 0; int sleep_time = 0; ZERO_STRUCT(tval); + GetTimeOfDay(&tval); - gettimeofday(&tval,NULL); - - tdiff = 1000000 *(tval.tv_sec - ldap_state->last_rebind.tv_sec) + - (tval.tv_usec - ldap_state->last_rebind.tv_usec); + tdiff = usec_time_diff(&tval, &ldap_state->last_rebind.tv_sec); + tdiff /= 1000; /* Convert to milliseconds. */ - sleep_time = ((1000*lp_ldap_replication_sleep())-tdiff)/1000; + sleep_time = lp_ldap_replication_sleep()-(int)tdiff; + sleep_time = MIN(sleep_time, MAX_LDAP_REPLICATION_SLEEP_TIME); if (sleep_time > 0) { /* we wait for the LDAP replication */ DEBUG(5,("smbldap_search: waiting %d milliseconds for LDAP replication.\n",sleep_time)); smb_msleep(sleep_time); DEBUG(5,("smbldap_search: go on!\n")); - ZERO_STRUCT(ldap_state->last_rebind); } + ZERO_STRUCT(ldap_state->last_rebind); } if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) { diff --git a/source/lib/snprintf.c b/source/lib/snprintf.c index 5b0cfa1ab33..79de3c0ca5d 100644 --- a/source/lib/snprintf.c +++ b/source/lib/snprintf.c @@ -817,7 +817,7 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) (*currlen)++; } - int vsnprintf (char *str, size_t count, const char *fmt, va_list args) + int smb_vsnprintf (char *str, size_t count, const char *fmt, va_list args) { return dopr(str, count, fmt, args); } diff --git a/source/lib/time.c b/source/lib/time.c index faca2cba879..e63e0b29659 100644 --- a/source/lib/time.c +++ b/source/lib/time.c @@ -754,3 +754,9 @@ BOOL nt_time_is_zero(NTTIME *nt) return True; return False; } + +SMB_BIG_INT usec_time_diff(struct timeval *larget, struct timeval *smallt) +{ + SMB_BIG_INT sec_diff = larget->tv_sec - smallt->tv_sec; + return (sec_diff * 1000000) + (SMB_BIG_INT)(larget->tv_usec - smallt->tv_usec); +} diff --git a/source/lib/username.c b/source/lib/username.c index ac5530b5c71..317935d396f 100644 --- a/source/lib/username.c +++ b/source/lib/username.c @@ -306,7 +306,7 @@ static BOOL user_in_netgroup_list(const char *user, const char *ngname) { #ifdef HAVE_NETGROUP static char *mydomain = NULL; - fstring lowercase_user, lowercase_ngname; + fstring lowercase_user; if (mydomain == NULL) yp_get_default_domain(&mydomain); @@ -318,25 +318,28 @@ static BOOL user_in_netgroup_list(const char *user, const char *ngname) DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", user, mydomain, ngname)); - DEBUG(5,("innetgr is %s\n", innetgr(ngname, NULL, user, mydomain) - ? "TRUE" : "FALSE")); - if (innetgr(ngname, NULL, user, mydomain)) + if (innetgr(ngname, NULL, user, mydomain)) { + DEBUG(5,("user_in_netgroup_list: Found\n")); return (True); + } else { - /* - * Ok, innetgr is case sensitive. Try once more with lowercase - * just in case. Attempt to fix #703. JRA. - */ + /* + * Ok, innetgr is case sensitive. Try once more with lowercase + * just in case. Attempt to fix #703. JRA. + */ - fstrcpy(lowercase_user, user); - strlower_m(lowercase_user); - fstrcpy(lowercase_ngname, ngname); - strlower_m(lowercase_ngname); + fstrcpy(lowercase_user, user); + strlower_m(lowercase_user); - if (innetgr(lowercase_ngname, NULL, lowercase_user, mydomain)) - return (True); + DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", + lowercase_user, mydomain, ngname)); + if (innetgr(ngname, NULL, lowercase_user, mydomain)) { + DEBUG(5,("user_in_netgroup_list: Found\n")); + return (True); + } + } #endif /* HAVE_NETGROUP */ return False; } diff --git a/source/lib/util.c b/source/lib/util.c index 9d7a2648c5b..554f5ee79da 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -1802,6 +1802,9 @@ void set_remote_arch(enum remote_arch_types type) case RA_SAMBA: fstrcpy(remote_arch,"Samba"); break; + case RA_CIFSFS: + fstrcpy(remote_arch,"CIFSFS"); + break; default: ra_type = RA_UNKNOWN; fstrcpy(remote_arch, "UNKNOWN"); @@ -2432,6 +2435,21 @@ BOOL unix_wild_match(const char *pattern, const char *string) return unix_do_match(p2, s2) == 0; } +/********************************************************************** + Converts a name to a fully qalified domain name. +***********************************************************************/ + +void name_to_fqdn(fstring fqdn, const char *name) +{ + struct hostent *hp = sys_gethostbyname(name); + if ( hp && hp->h_name && *hp->h_name ) { + DEBUG(10,("name_to_fqdn: lookup for %s -> %s.\n", name, hp->h_name)); + fstrcpy(fqdn,hp->h_name); + } else { + DEBUG(10,("name_to_fqdn: lookup for %s failed.\n", name)); + fstrcpy(fqdn, name); + } +} #ifdef __INSURE__ diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c index b6bfdca5cf9..4b9881a4499 100644 --- a/source/lib/util_sock.c +++ b/source/lib/util_sock.c @@ -52,6 +52,23 @@ static char *get_socket_addr(int fd) return addr_buf; } +static int get_socket_port(int fd) +{ + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + socklen_t length = sizeof(sa); + + if (fd == -1) + return -1; + + if (getsockname(fd, &sa, &length) < 0) { + DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) )); + return -1; + } + + return ntohs(sockin->sin_port); +} + /**************************************************************************** Determine if a file descriptor is in fact a socket. ****************************************************************************/ @@ -837,6 +854,11 @@ char *client_socket_addr(void) return get_socket_addr(client_fd); } +int client_socket_port(void) +{ + return get_socket_port(client_fd); +} + struct in_addr *client_inaddr(struct sockaddr *sa) { struct sockaddr_in *sockin = (struct sockaddr_in *) (sa); diff --git a/source/lib/util_str.c b/source/lib/util_str.c index 65ef306ed17..7c5fa11c92d 100644 --- a/source/lib/util_str.c +++ b/source/lib/util_str.c @@ -62,7 +62,7 @@ BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize) /* copy over the token */ pbuf = buff; for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) { - if (*s == '\"' || *s == '\'') { + if ( *s == '\"' ) { quoted = !quoted; } else { len++; diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c index e8bf4b08462..97b895a2418 100644 --- a/source/libads/kerberos.c +++ b/source/libads/kerberos.c @@ -79,9 +79,9 @@ int kerberos_kinit_password(const char *principal, const char *password, int tim return code; } - if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, NULL, + if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, password, kerb_prompter, - password, 0, NULL, NULL))) { + NULL, 0, NULL, NULL))) { krb5_free_principal(ctx, me); krb5_free_context(ctx); return code; diff --git a/source/libads/kerberos_keytab.c b/source/libads/kerberos_keytab.c new file mode 100644 index 00000000000..eec5f104fd9 --- /dev/null +++ b/source/libads/kerberos_keytab.c @@ -0,0 +1,554 @@ +/* + Unix SMB/CIFS implementation. + kerberos keytab utility library + Copyright (C) Andrew Tridgell 2001 + Copyright (C) Remus Koos 2001 + Copyright (C) Luke Howard 2003 + Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003 + Copyright (C) Guenther Deschner 2003 + Copyright (C) Rakesh Patel 2004 + Copyright (C) Dan Perry 2004 + Copyright (C) Jeremy Allison 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +#ifdef HAVE_KRB5 + +/********************************************************************** + Adds a single service principal, i.e. 'host' to the system keytab +***********************************************************************/ + +int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc) +{ + krb5_error_code ret = 0; + krb5_context context = NULL; + krb5_keytab keytab = NULL; + krb5_kt_cursor cursor; + krb5_keytab_entry kt_entry; + krb5_principal princ = NULL; + krb5_data password; + krb5_enctype *enctypes = NULL; + krb5_kvno kvno; + + char *principal = NULL; + char *princ_s = NULL; + char *password_s = NULL; +#ifndef MAX_KEYTAB_NAME_LEN +#define MAX_KEYTAB_NAME_LEN 1100 +#endif + char keytab_name[MAX_KEYTAB_NAME_LEN]; /* This MAX_NAME_LEN is a constant defined in krb5.h */ + fstring my_fqdn; + int i; + char *ktprinc = NULL; + + ZERO_STRUCT(kt_entry); + ZERO_STRUCT(cursor); + + initialize_krb5_error_table(); + ret = krb5_init_context(&context); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: could not krb5_init_context: %s\n",error_message(ret))); + return -1; + } +#ifdef HAVE_WRFILE_KEYTAB /* MIT */ + keytab_name[0] = 'W'; + keytab_name[1] = 'R'; + ret = krb5_kt_default_name(context, (char *) &keytab_name[2], MAX_KEYTAB_NAME_LEN - 4); +#else /* Heimdal */ + ret = krb5_kt_default_name(context, (char *) &keytab_name[0], MAX_KEYTAB_NAME_LEN - 2); +#endif + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_kt_default_name failed (%s)\n", error_message(ret))); + goto out; + } + DEBUG(2,("ads_keytab_add_entry: Using default system keytab: %s\n", (char *) &keytab_name)); + ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_kt_resolve failed (%s)\n", error_message(ret))); + goto out; + } + + /* retrieve the password */ + if (!secrets_init()) { + DEBUG(1,("ads_keytab_add_entry: secrets_init failed\n")); + ret = -1; + goto out; + } + password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); + if (!password_s) { + DEBUG(1,("ads_keytab_add_entry: failed to fetch machine password\n")); + ret = -1; + goto out; + } + password.data = password_s; + password.length = strlen(password_s); + + /* Construct our principal */ + name_to_fqdn(my_fqdn, global_myname()); + strlower_m(my_fqdn); + asprintf(&princ_s, "%s/%s@%s", srvPrinc, my_fqdn, lp_realm()); + + ret = krb5_parse_name(context, princ_s, &princ); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret))); + goto out; + } + + kvno = (krb5_kvno) ads_get_kvno(ads, global_myname()); + if (kvno == -1) { /* -1 indicates failure, everything else is OK */ + DEBUG(1,("ads_keytab_add_entry: ads_get_kvno failed to determine the system's kvno.\n")); + ret = -1; + goto out; + } + + /* Seek and delete old keytab entries */ + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret != KRB5_KT_END && ret != ENOENT ) { + DEBUG(3,("ads_keytab_add_entry: Will try to delete old keytab entries\n")); + while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) { + BOOL compare_ok = False; + + ret = krb5_unparse_name(context, kt_entry.principal, &ktprinc); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_unparse_name failed (%s)\n", error_message(ret))); + goto out; + } + + /*--------------------------------------------------------------------------- + * Save the entries with kvno - 1. This is what microsoft does + * to allow people with existing sessions that have kvno - 1 to still + * work. Otherwise, when the password for the machine changes, all + * kerberizied sessions will 'break' until either the client reboots or + * the client's session key expires and they get a new session ticket + * with the new kvno. + */ + +#ifdef HAVE_KRB5_KT_COMPARE + compare_ok = ((krb5_kt_compare(context, &kt_entry, princ, 0, 0) == True) && (kt_entry.vno != kvno - 1)); +#else + compare_ok = ((strcmp(ktprinc, princ_s) == 0) && (kt_entry.vno != kvno - 1)); +#endif + krb5_free_unparsed_name(context, ktprinc); + ktprinc = NULL; + + if (compare_ok) { + DEBUG(3,("ads_keytab_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n", + princ_s, kt_entry.vno)); + ret = krb5_kt_end_seq_get(context, keytab, &cursor); + ZERO_STRUCT(cursor); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get() failed (%s)\n", + error_message(ret))); + goto out; + } + ret = krb5_kt_remove_entry(context, keytab, &kt_entry); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n", + error_message(ret))); + goto out; + } + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_kt_start_seq failed (%s)\n", + error_message(ret))); + goto out; + } + ret = smb_krb5_kt_free_entry(context, &kt_entry); + ZERO_STRUCT(kt_entry); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n", + error_message(ret))); + goto out; + } + continue; + } + + /* Not a match, just free this entry and continue. */ + ret = smb_krb5_kt_free_entry(context, &kt_entry); + ZERO_STRUCT(kt_entry); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret))); + goto out; + } + } + + ret = krb5_kt_end_seq_get(context, keytab, &cursor); + ZERO_STRUCT(cursor); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get failed (%s)\n",error_message(ret))); + goto out; + } + } + + /* Ensure we don't double free. */ + ZERO_STRUCT(kt_entry); + ZERO_STRUCT(cursor); + + /* If we get here, we have deleted all the old entries with kvno's not equal to the current kvno-1. */ + + ret = get_kerberos_allowed_etypes(context,&enctypes); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: get_kerberos_allowed_etypes failed (%s)\n",error_message(ret))); + goto out; + } + + /* Now add keytab entries for all encryption types */ + for (i = 0; enctypes[i]; i++) { + krb5_keyblock *keyp; + +#if !defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) && !defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK) +#error krb5_keytab_entry has no key or keyblock member +#endif +#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */ + keyp = &kt_entry.key; +#endif +#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */ + keyp = &kt_entry.keyblock; +#endif + if (create_kerberos_key_from_string(context, princ, &password, keyp, enctypes[i])) { + continue; + } + + kt_entry.principal = princ; + kt_entry.vno = kvno; + + DEBUG(3,("ads_keytab_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n", + princ_s, enctypes[i], kt_entry.vno)); + ret = krb5_kt_add_entry(context, keytab, &kt_entry); + krb5_free_keyblock_contents(context, keyp); + ZERO_STRUCT(kt_entry); + if (ret) { + DEBUG(1,("ads_keytab_add_entry: adding entry to keytab failed (%s)\n", error_message(ret))); + goto out; + } + } + + krb5_kt_close(context, keytab); + keytab = NULL; /* Done with keytab now. No double free. */ + + /* Update the LDAP with the SPN */ + DEBUG(3,("ads_keytab_add_entry: Attempting to add/update '%s'\n", princ_s)); + if (!ADS_ERR_OK(ads_add_service_principal_name(ads, global_myname(), srvPrinc))) { + DEBUG(1,("ads_keytab_add_entry: ads_add_service_principcal_name failed.\n")); + goto out; + } + +out: + + SAFE_FREE(principal); + SAFE_FREE(password_s); + SAFE_FREE(princ_s); + + { + krb5_keytab_entry zero_kt_entry; + ZERO_STRUCT(zero_kt_entry); + if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { + smb_krb5_kt_free_entry(context, &kt_entry); + } + } + if (princ) { + krb5_free_principal(context, princ); + } + if (enctypes) { + free_kerberos_etypes(context, enctypes); + } + + { + krb5_kt_cursor zero_csr; + ZERO_STRUCT(zero_csr); + if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { + krb5_kt_end_seq_get(context, keytab, &cursor); + } + } + if (keytab) { + krb5_kt_close(context, keytab); + } + if (context) { + krb5_free_context(context); + } + return (int)ret; +} + +/********************************************************************** + Flushes all entries from the system keytab. +***********************************************************************/ + +int ads_keytab_flush(ADS_STRUCT *ads) +{ + krb5_error_code ret = 0; + krb5_context context = NULL; + krb5_keytab keytab = NULL; + krb5_kt_cursor cursor; + krb5_keytab_entry kt_entry; + krb5_kvno kvno; + char keytab_name[MAX_KEYTAB_NAME_LEN]; + + ZERO_STRUCT(kt_entry); + ZERO_STRUCT(cursor); + + initialize_krb5_error_table(); + ret = krb5_init_context(&context); + if (ret) { + DEBUG(1,("ads_keytab_flush: could not krb5_init_context: %s\n",error_message(ret))); + return ret; + } +#ifdef HAVE_WRFILE_KEYTAB + keytab_name[0] = 'W'; + keytab_name[1] = 'R'; + ret = krb5_kt_default_name(context, (char *) &keytab_name[2], MAX_KEYTAB_NAME_LEN - 4); +#else + ret = krb5_kt_default_name(context, (char *) &keytab_name[0], MAX_KEYTAB_NAME_LEN - 2); +#endif + if (ret) { + DEBUG(1,("ads_keytab_flush: krb5_kt_default failed (%s)\n", error_message(ret))); + goto out; + } + DEBUG(3,("ads_keytab_flush: Using default keytab: %s\n", (char *) &keytab_name)); + ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab); + if (ret) { + DEBUG(1,("ads_keytab_flush: krb5_kt_default failed (%s)\n", error_message(ret))); + goto out; + } + ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab); + if (ret) { + DEBUG(1,("ads_keytab_flush: krb5_kt_default failed (%s)\n", error_message(ret))); + goto out; + } + + kvno = (krb5_kvno) ads_get_kvno(ads, global_myname()); + if (kvno == -1) { /* -1 indicates a failure */ + DEBUG(1,("ads_keytab_flush: Error determining the system's kvno.\n")); + goto out; + } + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret != KRB5_KT_END && ret != ENOENT) { + while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) { + ret = krb5_kt_end_seq_get(context, keytab, &cursor); + ZERO_STRUCT(cursor); + if (ret) { + DEBUG(1,("ads_keytab_flush: krb5_kt_end_seq_get() failed (%s)\n",error_message(ret))); + goto out; + } + ret = krb5_kt_remove_entry(context, keytab, &kt_entry); + if (ret) { + DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret))); + goto out; + } + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret) { + DEBUG(1,("ads_keytab_flush: krb5_kt_start_seq failed (%s)\n",error_message(ret))); + goto out; + } + ret = smb_krb5_kt_free_entry(context, &kt_entry); + ZERO_STRUCT(kt_entry); + if (ret) { + DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret))); + goto out; + } + } + } + + /* Ensure we don't double free. */ + ZERO_STRUCT(kt_entry); + ZERO_STRUCT(cursor); + + if (!ADS_ERR_OK(ads_clear_service_principal_names(ads, global_myname()))) { + DEBUG(1,("ads_keytab_flush: Error while clearing service principal listings in LDAP.\n")); + goto out; + } + +out: + + { + krb5_keytab_entry zero_kt_entry; + ZERO_STRUCT(zero_kt_entry); + if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { + smb_krb5_kt_free_entry(context, &kt_entry); + } + } + { + krb5_kt_cursor zero_csr; + ZERO_STRUCT(zero_csr); + if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { + krb5_kt_end_seq_get(context, keytab, &cursor); + } + } + if (keytab) { + krb5_kt_close(context, keytab); + } + if (context) { + krb5_free_context(context); + } + return ret; +} + +/********************************************************************** + Adds all the required service principals to the system keytab. +***********************************************************************/ + +int ads_keytab_create_default(ADS_STRUCT *ads) +{ + krb5_error_code ret = 0; + krb5_context context = NULL; + krb5_keytab keytab = NULL; + krb5_kt_cursor cursor; + krb5_keytab_entry kt_entry; + krb5_kvno kvno; + int i, found = 0; + char **oldEntries = NULL; + + ret = ads_keytab_add_entry(ads, "host"); + if (ret) { + DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'host'.\n")); + return ret; + } + ret = ads_keytab_add_entry(ads, "cifs"); + if (ret) { + DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'cifs'.\n")); + return ret; + } + + kvno = (krb5_kvno) ads_get_kvno(ads, global_myname()); + if (kvno == -1) { + DEBUG(1,("ads_keytab_create_default: ads_get_kvno failed to determine the system's kvno.\n")); + return -1; + } + + DEBUG(3,("ads_keytab_create_default: Searching for keytab entries to preserve and update.\n")); + /* Now loop through the keytab and update any other existing entries... */ + + ZERO_STRUCT(kt_entry); + ZERO_STRUCT(cursor); + + initialize_krb5_error_table(); + ret = krb5_init_context(&context); + if (ret) { + DEBUG(1,("ads_keytab_create_default: could not krb5_init_context: %s\n",error_message(ret))); + return ret; + } + ret = krb5_kt_default(context, &keytab); + if (ret) { + DEBUG(1,("ads_keytab_create_default: krb5_kt_default failed (%s)\n",error_message(ret))); + goto done; + } + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret != KRB5_KT_END && ret != ENOENT ) { + while ((ret = krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) == 0) { + smb_krb5_kt_free_entry(context, &kt_entry); + ZERO_STRUCT(kt_entry); + found++; + } + } + krb5_kt_end_seq_get(context, keytab, &cursor); + ZERO_STRUCT(cursor); + + /* + * Hmmm. There is no "rewind" function for the keytab. This means we have a race condition + * where someone else could add entries after we've counted them. Re-open asap to minimise + * the race. JRA. + */ + + DEBUG(3, ("ads_keytab_create_default: Found %d entries in the keytab.\n", found)); + if (!found) { + goto done; + } + oldEntries = (char **) malloc(found * sizeof(char *)); + if (!oldEntries) { + DEBUG(1,("ads_keytab_create_default: Failed to allocate space to store the old keytab entries (malloc failed?).\n")); + ret = -1; + goto done; + } + memset(oldEntries, '\0', found * sizeof(char *)); + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret != KRB5_KT_END && ret != ENOENT ) { + while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) { + if (kt_entry.vno != kvno) { + char *ktprinc = NULL; + char *p; + + /* This returns a malloc'ed string in ktprinc. */ + ret = krb5_unparse_name(context, kt_entry.principal, &ktprinc); + if (ret) { + DEBUG(1,("krb5_unparse_name failed (%s)\n", error_message(ret))); + goto done; + } + /* + * From looking at the krb5 source they don't seem to take locale + * or mb strings into account. Maybe this is because they assume utf8 ? + * In this case we may need to convert from utf8 to mb charset here ? JRA. + */ + p = strchr_m(ktprinc, '/'); + if (p) { + *p = '\0'; + } + for (i = 0; i < found; i++) { + if (!oldEntries[i]) { + oldEntries[i] = ktprinc; + break; + } + if (!strcmp(oldEntries[i], ktprinc)) { + krb5_free_unparsed_name(context, ktprinc); + break; + } + } + if (i == found) { + krb5_free_unparsed_name(context, ktprinc); + } + } + smb_krb5_kt_free_entry(context, &kt_entry); + ZERO_STRUCT(kt_entry); + } + ret = 0; + for (i = 0; oldEntries[i]; i++) { + ret |= ads_keytab_add_entry(ads, oldEntries[i]); + krb5_free_unparsed_name(context, oldEntries[i]); + } + krb5_kt_end_seq_get(context, keytab, &cursor); + } + ZERO_STRUCT(cursor); + +done: + + SAFE_FREE(oldEntries); + + { + krb5_keytab_entry zero_kt_entry; + ZERO_STRUCT(zero_kt_entry); + if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { + smb_krb5_kt_free_entry(context, &kt_entry); + } + } + { + krb5_kt_cursor zero_csr; + ZERO_STRUCT(zero_csr); + if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { + krb5_kt_end_seq_get(context, keytab, &cursor); + } + } + if (keytab) { + krb5_kt_close(context, keytab); + } + if (context) { + krb5_free_context(context); + } + return ret; +} +#endif /* HAVE_KRB5 */ diff --git a/source/libads/kerberos_verify.c b/source/libads/kerberos_verify.c index 47559c1abb7..bdac22a9022 100644 --- a/source/libads/kerberos_verify.c +++ b/source/libads/kerberos_verify.c @@ -26,10 +26,182 @@ #ifdef HAVE_KRB5 -/* - verify an incoming ticket and parse out the principal name and - authorization_data if available -*/ +/********************************************************************************** + Try to verify a ticket using the system keytab... the system keytab has kvno -1 entries, so + it's more like what microsoft does... see comment in utils/net_ads.c in the + ads_keytab_add_entry function for details. +***********************************************************************************/ + +static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, + const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt) +{ + krb5_error_code ret = 0; + BOOL auth_ok = False; + + krb5_keytab keytab = NULL; + krb5_kt_cursor cursor; + krb5_keytab_entry kt_entry; + char *princ_name = NULL; + + ZERO_STRUCT(kt_entry); + ZERO_STRUCT(cursor); + + ret = krb5_kt_default(context, &keytab); + if (ret) { + DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_default failed (%s)\n", error_message(ret))); + goto out; + } + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret) { + DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret))); + goto out; + } + + while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) { + ret = krb5_unparse_name(context, kt_entry.principal, &princ_name); + if (ret) { + DEBUG(1, ("ads_keytab_verify_ticket: krb5_unparse_name failed (%s)\n", error_message(ret))); + goto out; + } + /* Look for a CIFS ticket */ + if (!StrnCaseCmp(princ_name, "cifs/", 5)) { +#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK + krb5_auth_con_setuseruserkey(context, auth_context, &kt_entry.keyblock); +#else + krb5_auth_con_setuseruserkey(context, auth_context, &kt_entry.key); +#endif + + p_packet->length = ticket->length; + p_packet->data = (krb5_pointer)ticket->data; + + if (!(ret = krb5_rd_req(context, &auth_context, p_packet, NULL, NULL, NULL, pp_tkt))) { + unsigned int keytype; + krb5_free_unparsed_name(context, princ_name); + princ_name = NULL; +#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK + keytype = (unsigned int) kt_entry.keyblock.keytype; +#else + keytype = (unsigned int) kt_entry.key.enctype; +#endif + DEBUG(10,("ads_keytab_verify_ticket: enc type [%u] decrypted message !\n", + keytype)); + auth_ok = True; + break; + } + } + krb5_free_unparsed_name(context, princ_name); + princ_name = NULL; + } + if (ret && ret != KRB5_KT_END) { + /* This failed because something went wrong, not because the keytab file was empty. */ + DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_next_entry failed (%s)\n", error_message(ret))); + goto out; + } + + out: + + if (princ_name) { + krb5_free_unparsed_name(context, princ_name); + } + { + krb5_kt_cursor zero_csr; + ZERO_STRUCT(zero_csr); + if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { + krb5_kt_end_seq_get(context, keytab, &cursor); + } + } + if (keytab) { + krb5_kt_close(context, keytab); + } + + return auth_ok; +} + +/********************************************************************************** + Try to verify a ticket using the secrets.tdb. +***********************************************************************************/ + +static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context, + krb5_principal host_princ, + const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt) +{ + krb5_error_code ret = 0; + BOOL auth_ok = False; + char *password_s = NULL; + krb5_data password; + krb5_enctype *enctypes = NULL; + int i; + + if (!secrets_init()) { + DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n")); + return False; + } + + password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); + if (!password_s) { + DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n")); + return False; + } + + password.data = password_s; + password.length = strlen(password_s); + + /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ + + if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) { + DEBUG(1,("ads_secrets_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n", + error_message(ret))); + goto out; + } + + p_packet->length = ticket->length; + p_packet->data = (krb5_pointer)ticket->data; + + /* We need to setup a auth context with each possible encoding type in turn. */ + for (i=0;enctypes[i];i++) { + krb5_keyblock *key = NULL; + + if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) { + goto out; + } + + if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) { + SAFE_FREE(key); + continue; + } + + krb5_auth_con_setuseruserkey(context, auth_context, key); + + krb5_free_keyblock(context, key); + + if (!(ret = krb5_rd_req(context, &auth_context, p_packet, + NULL, + NULL, NULL, pp_tkt))) { + DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", + (unsigned int)enctypes[i] )); + auth_ok = True; + break; + } + + DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10, + ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n", + (unsigned int)enctypes[i], error_message(ret))); + } + + out: + + free_kerberos_etypes(context, enctypes); + SAFE_FREE(password_s); + + return auth_ok; +} + +/********************************************************************************** + Verify an incoming ticket and parse out the principal name and + authorization_data if available. +***********************************************************************************/ + NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, char **principal, DATA_BLOB *auth_data, DATA_BLOB *ap_rep, @@ -41,43 +213,21 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, krb5_data packet; krb5_ticket *tkt = NULL; krb5_rcache rcache = NULL; - int ret, i; - krb5_keyblock *key = NULL; + int ret; - krb5_principal host_princ; + krb5_principal host_princ = NULL; char *host_princ_s = NULL; - BOOL free_host_princ = False; BOOL got_replay_mutex = False; fstring myname; - char *password_s = NULL; - krb5_data password; - krb5_enctype *enctypes = NULL; -#if 0 - krb5_address local_addr; - krb5_address remote_addr; -#endif BOOL auth_ok = False; ZERO_STRUCT(packet); - ZERO_STRUCT(password); ZERO_STRUCTP(auth_data); ZERO_STRUCTP(ap_rep); + ZERO_STRUCTP(session_key); - if (!secrets_init()) { - DEBUG(1,("ads_verify_ticket: secrets_init failed\n")); - return NT_STATUS_LOGON_FAILURE; - } - - password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); - if (!password_s) { - DEBUG(1,("ads_verify_ticket: failed to fetch machine password\n")); - return NT_STATUS_LOGON_FAILURE; - } - - password.data = password_s; - password.length = strlen(password_s); - + initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret))); @@ -87,7 +237,6 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, ret = krb5_set_default_realm(context, realm); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret))); - sret = NT_STATUS_LOGON_FAILURE; goto out; } @@ -98,22 +247,29 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, ret = krb5_auth_con_init(context, &auth_context); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret))); - sret = NT_STATUS_LOGON_FAILURE; goto out; } - fstrcpy(myname, global_myname()); + name_to_fqdn(myname, global_myname()); strlower_m(myname); - asprintf(&host_princ_s, "HOST/%s@%s", myname, lp_realm()); + asprintf(&host_princ_s, "host/%s@%s", myname, lp_realm()); ret = krb5_parse_name(context, host_princ_s, &host_princ); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_parse_name(%s) failed (%s)\n", host_princ_s, error_message(ret))); - sret = NT_STATUS_LOGON_FAILURE; goto out; } - free_host_princ = True; + + /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5 + * code surrounding the replay cache... */ + + if (!grab_server_mutex("replay cache mutex")) { + DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n")); + goto out; + } + + got_replay_mutex = True; /* * JRA. We must set the rcache here. This will prevent replay attacks. @@ -122,67 +278,21 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache failed (%s)\n", error_message(ret))); - sret = NT_STATUS_LOGON_FAILURE; goto out; } ret = krb5_auth_con_setrcache(context, auth_context, rcache); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache failed (%s)\n", error_message(ret))); - sret = NT_STATUS_LOGON_FAILURE; goto out; } - /* CIFS doesn't use addresses in tickets. This would breat NAT. JRA */ - - if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) { - DEBUG(1,("ads_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n", - error_message(ret))); - sret = NT_STATUS_LOGON_FAILURE; - goto out; + if (lp_use_kerberos_keytab()) { + auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &packet, &tkt); } - - /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5 - * code surrounding the replay cache... */ - - if (!grab_server_mutex("replay cache mutex")) { - DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n")); - sret = NT_STATUS_LOGON_FAILURE; - goto out; - } - - got_replay_mutex = True; - - /* We need to setup a auth context with each possible encoding type in turn. */ - for (i=0;enctypes[i];i++) { - if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) { - sret = NT_STATUS_NO_MEMORY; - goto out; - } - - if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) { - continue; - } - - krb5_auth_con_setuseruserkey(context, auth_context, key); - - krb5_free_keyblock(context, key); - - packet.length = ticket->length; - packet.data = (krb5_pointer)ticket->data; - - if (!(ret = krb5_rd_req(context, &auth_context, &packet, - NULL, - NULL, NULL, &tkt))) { - DEBUG(10,("ads_verify_ticket: enc type [%u] decrypted message !\n", - (unsigned int)enctypes[i] )); - auth_ok = True; - break; - } - - DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10, - ("ads_verify_ticket: enc type [%u] failed to decrypt with error %s\n", - (unsigned int)enctypes[i], error_message(ret))); + if (!auth_ok) { + auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, + ticket, &packet, &tkt); } release_server_mutex(); @@ -191,7 +301,6 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, if (!auth_ok) { DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", error_message(ret))); - sret = NT_STATUS_LOGON_FAILURE; goto out; } @@ -199,12 +308,12 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, if (ret) { DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", error_message(ret))); - sret = NT_STATUS_LOGON_FAILURE; goto out; } *ap_rep = data_blob(packet.data, packet.length); - free(packet.data); + SAFE_FREE(packet.data); + packet.length = 0; get_krb5_smb_session_key(context, auth_context, session_key, True); dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); @@ -241,29 +350,35 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, out: - if (got_replay_mutex) + if (got_replay_mutex) { release_server_mutex(); + } - if (!NT_STATUS_IS_OK(sret)) + if (!NT_STATUS_IS_OK(sret)) { data_blob_free(auth_data); + } - if (!NT_STATUS_IS_OK(sret)) + if (!NT_STATUS_IS_OK(sret)) { data_blob_free(ap_rep); + } - if (free_host_princ) + if (host_princ) { krb5_free_principal(context, host_princ); + } - if (tkt != NULL) + if (tkt != NULL) { krb5_free_ticket(context, tkt); - free_kerberos_etypes(context, enctypes); - SAFE_FREE(password_s); + } + SAFE_FREE(host_princ_s); - if (auth_context) + if (auth_context) { krb5_auth_con_free(context, auth_context); + } - if (context) + if (context) { krb5_free_context(context); + } return sret; } diff --git a/source/libads/krb5_setpw.c b/source/libads/krb5_setpw.c index 5c859f0e995..84595212e6c 100644 --- a/source/libads/krb5_setpw.c +++ b/source/libads/krb5_setpw.c @@ -56,7 +56,7 @@ static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password) princ = strdup(principal); - if ((c = strchr(princ, '/')) == NULL) { + if ((c = strchr_m(princ, '/')) == NULL) { c = princ; } else { *c = '\0'; @@ -66,7 +66,7 @@ static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password) princ_part2 = c; - if ((c = strchr(c, '@')) != NULL) { + if ((c = strchr_m(c, '@')) != NULL) { *c = '\0'; c++; realm = c; @@ -462,14 +462,21 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, { ADS_STATUS aret; - krb5_error_code ret; + krb5_error_code ret = 0; krb5_context context = NULL; - krb5_principal principal; - char *princ_name; - char *realm; - krb5_creds creds, *credsp; + krb5_principal principal = NULL; + char *princ_name = NULL; + char *realm = NULL; + krb5_creds creds, *credsp = NULL; +#if KRB5_PRINC_REALM_RETURNS_REALM + krb5_realm orig_realm; +#else + krb5_data orig_realm; +#endif krb5_ccache ccache = NULL; + ZERO_STRUCT(creds); + ret = krb5_init_context(&context); if (ret) { DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret))); @@ -487,14 +494,19 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, return ADS_ERROR_KRB5(ret); } - ZERO_STRUCT(creds); - - realm = strchr(princ, '@'); + realm = strchr_m(princ, '@'); + if (!realm) { + krb5_cc_close(context, ccache); + krb5_free_context(context); + DEBUG(1,("Failed to get realm\n")); + return ADS_ERROR_KRB5(-1); + } realm++; asprintf(&princ_name, "kadmin/changepw@%s", realm); ret = krb5_parse_name(context, princ_name, &creds.server); if (ret) { + krb5_cc_close(context, ccache); krb5_free_context(context); DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); @@ -504,16 +516,23 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, /* parse the principal we got as a function argument */ ret = krb5_parse_name(context, princ, &principal); if (ret) { + krb5_cc_close(context, ccache); + krb5_free_principal(context, creds.server); krb5_free_context(context); DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret))); return ADS_ERROR_KRB5(ret); } - krb5_princ_set_realm(context, creds.server, - krb5_princ_realm(context, principal)); + /* The creds.server principal takes ownership of this memory. + Remember to set back to original value before freeing. */ + orig_realm = *krb5_princ_realm(context, creds.server); + krb5_princ_set_realm(context, creds.server, krb5_princ_realm(context, principal)); ret = krb5_cc_get_principal(context, ccache, &creds.client); if (ret) { + krb5_cc_close(context, ccache); + krb5_princ_set_realm(context, creds.server, &orig_realm); + krb5_free_principal(context, creds.server); krb5_free_principal(context, principal); krb5_free_context(context); DEBUG(1,("Failed to get principal from ccache (%s)\n", @@ -523,7 +542,10 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); if (ret) { + krb5_cc_close(context, ccache); krb5_free_principal(context, creds.client); + krb5_princ_set_realm(context, creds.server, &orig_realm); + krb5_free_principal(context, creds.server); krb5_free_principal(context, principal); krb5_free_context(context); DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret))); @@ -538,7 +560,10 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, krb5_free_creds(context, credsp); krb5_free_principal(context, creds.client); + krb5_princ_set_realm(context, creds.server, &orig_realm); + krb5_free_principal(context, creds.server); krb5_free_principal(context, principal); + krb5_cc_close(context, ccache); krb5_free_context(context); return aret; diff --git a/source/libads/ldap.c b/source/libads/ldap.c index e018eeb2da9..78ea9f1497d 100644 --- a/source/libads/ldap.c +++ b/source/libads/ldap.c @@ -37,6 +37,35 @@ * codepoints in UTF-8). This may have to change at some point **/ +static SIG_ATOMIC_T gotalarm; + +/*************************************************************** + Signal function to tell us we timed out. +****************************************************************/ + +static void gotalarm_sig(void) +{ + gotalarm = 1; +} + + LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to) +{ + LDAP *ldp = NULL; + + /* Setup timeout */ + gotalarm = 0; + CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); + alarm(to); + /* End setup timeout. */ + + ldp = ldap_open(server, port); + + /* Teardown timeout. */ + CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN); + alarm(0); + + return ldp; +} /* try a connection to a given ldap server, returning True and setting the servers IP @@ -58,7 +87,7 @@ static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port) /* this copes with inet_ntoa brokenness */ srv = strdup(server); - ads->ld = ldap_open(srv, port); + ads->ld = ldap_open_with_timeout(srv, port, lp_ldap_timeout()); if (!ads->ld) { free(srv); return False; @@ -226,11 +255,10 @@ got_connection: ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version); if (!ads->auth.user_name) { - /* by default use the machine account */ - fstring myname; - fstrcpy(myname, global_myname()); - strlower_m(myname); - asprintf(&ads->auth.user_name, "HOST/%s", myname); + /* have to use the userPrincipalName value here and + not servicePrincipalName; found by Guenther Deschner @ Sernet */ + + asprintf(&ads->auth.user_name, "host/%s", global_myname() ); } if (!ads->auth.realm) { @@ -730,7 +758,7 @@ char *ads_get_dn(ADS_STRUCT *ads, void *msg) * @param host Hostname to search for * @return status of search **/ -ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host) +ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *machine) { ADS_STATUS status; char *expr; @@ -738,13 +766,13 @@ ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host) /* the easiest way to find a machine account anywhere in the tree is to look for hostname$ */ - if (asprintf(&expr, "(samAccountName=%s$)", host) == -1) { + if (asprintf(&expr, "(samAccountName=%s$)", machine) == -1) { DEBUG(1, ("asprintf failed!\n")); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } status = ads_search(ads, res, expr, attrs); - free(expr); + SAFE_FREE(expr); return status; } @@ -979,18 +1007,251 @@ char *ads_ou_string(const char *org_unit) return ads_build_path(org_unit, "\\/", "ou=", 1); } +/** + * Adds (appends) an item to an attribute array, rather then + * replacing the whole list + * @param ctx An initialized TALLOC_CTX + * @param mods An initialized ADS_MODLIST + * @param name name of the ldap attribute to append to + * @param vals an array of values to add + * @return status of addition + **/ +ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods, + const char *name, const char **vals) +{ + return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name, (const void **) vals); +} -/* - add a machine account to the ADS server -*/ -static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, +/** + * Determines the computer account's current KVNO via an LDAP lookup + * @param ads An initialized ADS_STRUCT + * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account. + * @return the kvno for the computer account, or -1 in case of a failure. + **/ + +uint32 ads_get_kvno(ADS_STRUCT *ads, const char *machine_name) +{ + LDAPMessage *res = NULL; + uint32 kvno = (uint32)-1; /* -1 indicates a failure */ + char *filter; + const char *attrs[] = {"msDS-KeyVersionNumber", NULL}; + char *dn_string = NULL; + ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS); + + DEBUG(5,("ads_get_kvno: Searching for host %s\n", machine_name)); + if (asprintf(&filter, "(samAccountName=%s$)", machine_name) == -1) { + return kvno; + } + ret = ads_search(ads, (void**) &res, filter, attrs); + SAFE_FREE(filter); + if (!ADS_ERR_OK(ret) && ads_count_replies(ads, res)) { + DEBUG(1,("ads_get_kvno: Computer Account For %s not found.\n", machine_name)); + ads_msgfree(ads, res); + return kvno; + } + + dn_string = ads_get_dn(ads, res); + if (!dn_string) { + DEBUG(0,("ads_get_kvno: out of memory.\n")); + ads_msgfree(ads, res); + return kvno; + } + DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string)); + ads_memfree(ads, dn_string); + + /* --------------------------------------------------------- + * 0 is returned as a default KVNO from this point on... + * This is done because Windows 2000 does not support key + * version numbers. Chances are that a failure in the next + * step is simply due to Windows 2000 being used for a + * domain controller. */ + kvno = 0; + + if (!ads_pull_uint32(ads, res, "msDS-KeyVersionNumber", &kvno)) { + DEBUG(3,("ads_get_kvno: Error Determining KVNO!\n")); + DEBUG(3,("ads_get_kvno: Windows 2000 does not support KVNO's, so this may be normal.\n")); + ads_msgfree(ads, res); + return kvno; + } + + /* Success */ + DEBUG(5,("ads_get_kvno: Looked Up KVNO of: %d\n", kvno)); + ads_msgfree(ads, res); + return kvno; +} + +/** + * This clears out all registered spn's for a given hostname + * @param ads An initilaized ADS_STRUCT + * @param machine_name the NetBIOS name of the computer. + * @return 0 upon success, non-zero otherwise. + **/ + +ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machine_name) +{ + TALLOC_CTX *ctx; + LDAPMessage *res = NULL; + ADS_MODLIST mods; + const char *servicePrincipalName[1] = {NULL}; + ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS); + char *dn_string = NULL; + + ret = ads_find_machine_acct(ads, (void **)&res, machine_name); + if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) { + DEBUG(5,("ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation.\n", machine_name)); + DEBUG(5,("ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared.\n", machine_name)); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + DEBUG(5,("ads_clear_service_principal_names: Host account for %s found\n", machine_name)); + ctx = talloc_init("ads_clear_service_principal_names"); + if (!ctx) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + if (!(mods = ads_init_mods(ctx))) { + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + ret = ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName); + if (!ADS_ERR_OK(ret)) { + DEBUG(1,("ads_clear_service_principal_names: Error creating strlist.\n")); + ads_msgfree(ads, res); + talloc_destroy(ctx); + return ret; + } + dn_string = ads_get_dn(ads, res); + if (!dn_string) { + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + ret = ads_gen_mod(ads, dn_string, mods); + ads_memfree(ads,dn_string); + if (!ADS_ERR_OK(ret)) { + DEBUG(1,("ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP\n", + machine_name)); + ads_msgfree(ads, res); + talloc_destroy(ctx); + return ret; + } + + ads_msgfree(ads, res); + talloc_destroy(ctx); + return ret; +} + +/** + * This adds a service principal name to an existing computer account + * (found by hostname) in AD. + * @param ads An initialized ADS_STRUCT + * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account. + * @param spn A string of the service principal to add, i.e. 'host' + * @return 0 upon sucess, or non-zero if a failure occurs + **/ + +ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_name, const char *spn) +{ + ADS_STATUS ret; + TALLOC_CTX *ctx; + LDAPMessage *res = NULL; + char *host_spn, *host_upn, *psp1, *psp2; + ADS_MODLIST mods; + fstring my_fqdn; + char *dn_string = NULL; + const char *servicePrincipalName[3] = {NULL, NULL, NULL}; + + ret = ads_find_machine_acct(ads, (void **)&res, machine_name); + if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) { + DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n", + machine_name)); + DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principal '%s/%s@%s' has NOT been added.\n", + spn, machine_name, ads->config.realm)); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + DEBUG(1,("ads_add_service_principal_name: Host account for %s found\n", machine_name)); + if (!(ctx = talloc_init("ads_add_service_principal_name"))) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + name_to_fqdn(my_fqdn, machine_name); + if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", my_fqdn))) { + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm))) { + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + /* Add the extra principal */ + psp1 = talloc_asprintf(ctx, "%s/%s", spn, machine_name); + strupper_m(psp1); + strlower_m(&psp1[strlen(spn)]); + DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp1, machine_name)); + servicePrincipalName[0] = psp1; + psp2 = talloc_asprintf(ctx, "%s/%s.%s", spn, machine_name, ads->config.realm); + strupper_m(psp2); + strlower_m(&psp2[strlen(spn)]); + DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp2, machine_name)); + servicePrincipalName[1] = psp2; + + if (!(mods = ads_init_mods(ctx))) { + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + ret = ads_add_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName); + if (!ADS_ERR_OK(ret)) { + DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n")); + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ret; + } + dn_string = ads_get_dn(ads, res); + if (!dn_string) { + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + ret = ads_gen_mod(ads, dn_string, mods); + ads_memfree(ads,dn_string); + if (!ADS_ERR_OK(ret)) { + DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n")); + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ret; + } + + talloc_destroy(ctx); + ads_msgfree(ads, res); + return ret; +} + +/** + * adds a machine account to the ADS server + * @param ads An intialized ADS_STRUCT + * @param machine_name - the NetBIOS machine name of this account. + * @param account_type A number indicating the type of account to create + * @param org_unit The LDAP path in which to place this account + * @return 0 upon success, or non-zero otherwise +**/ + +static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *machine_name, uint32 account_type, const char *org_unit) { ADS_STATUS ret, status; char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr; - char *ou_str; TALLOC_CTX *ctx; ADS_MODLIST mods; const char *objectClass[] = {"top", "person", "organizationalPerson", @@ -999,87 +1260,106 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, char *psp, *psp2; unsigned acct_control; unsigned exists=0; - LDAPMessage *res; + fstring my_fqdn; + LDAPMessage *res = NULL; - status = ads_find_machine_acct(ads, (void **)&res, hostname); + if (!(ctx = talloc_init("ads_add_machine_acct"))) + return ADS_ERROR(LDAP_NO_MEMORY); + + ret = ADS_ERROR(LDAP_NO_MEMORY); + + name_to_fqdn(my_fqdn, machine_name); + + status = ads_find_machine_acct(ads, (void **)&res, machine_name); if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) { - DEBUG(0, ("Host account for %s already exists - modifying old account\n", hostname)); + char *dn_string = ads_get_dn(ads, res); + if (!dn_string) { + DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n")); + goto done; + } + new_dn = talloc_strdup(ctx, dn_string); + ads_memfree(ads,dn_string); + DEBUG(0, ("ads_add_machine_acct: Host account for %s already exists - modifying old account\n", + machine_name)); exists=1; - } + } else { + char *ou_str = ads_ou_string(org_unit); + if (!ou_str) { + DEBUG(1, ("ads_add_machine_acct: ads_ou_string returned NULL (malloc failure?)\n")); + goto done; + } + new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", machine_name, ou_str, + ads->config.bind_path); - if (!(ctx = talloc_init("machine_account"))) - return ADS_ERROR(LDAP_NO_MEMORY); + SAFE_FREE(ou_str); + } - ret = ADS_ERROR(LDAP_NO_MEMORY); + if (!new_dn) { + goto done; + } - if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", hostname))) + if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", machine_name))) goto done; if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm))) goto done; - ou_str = ads_ou_string(org_unit); - if (!ou_str) { - DEBUG(1, ("ads_ou_string returned NULL (malloc failure?)\n")); - goto done; - } - new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str, - ads->config.bind_path); - servicePrincipalName[0] = talloc_asprintf(ctx, "HOST/%s", hostname); + servicePrincipalName[0] = talloc_asprintf(ctx, "HOST/%s", machine_name); psp = talloc_asprintf(ctx, "HOST/%s.%s", - hostname, - ads->config.realm); + machine_name, + ads->config.realm); strlower_m(&psp[5]); servicePrincipalName[1] = psp; - servicePrincipalName[2] = talloc_asprintf(ctx, "CIFS/%s", hostname); + servicePrincipalName[2] = talloc_asprintf(ctx, "CIFS/%s", machine_name); psp2 = talloc_asprintf(ctx, "CIFS/%s.%s", - hostname, + machine_name, ads->config.realm); strlower_m(&psp2[5]); servicePrincipalName[3] = psp2; - free(ou_str); - if (!new_dn) - goto done; - - if (!(samAccountName = talloc_asprintf(ctx, "%s$", hostname))) + if (!(samAccountName = talloc_asprintf(ctx, "%s$", machine_name))) { goto done; + } acct_control = account_type | UF_DONT_EXPIRE_PASSWD; #ifndef ENCTYPE_ARCFOUR_HMAC acct_control |= UF_USE_DES_KEY_ONLY; #endif - if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control))) + if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control))) { goto done; + } - if (!(mods = ads_init_mods(ctx))) + if (!(mods = ads_init_mods(ctx))) { goto done; + } if (!exists) { - ads_mod_str(ctx, &mods, "cn", hostname); + ads_mod_str(ctx, &mods, "cn", machine_name); ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName); ads_mod_str(ctx, &mods, "userAccountControl", controlstr); ads_mod_strlist(ctx, &mods, "objectClass", objectClass); } - ads_mod_str(ctx, &mods, "dNSHostName", hostname); + ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn); ads_mod_str(ctx, &mods, "userPrincipalName", host_upn); ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName); ads_mod_str(ctx, &mods, "operatingSystem", "Samba"); ads_mod_str(ctx, &mods, "operatingSystemVersion", SAMBA_VERSION_STRING); - if (!exists) + if (!exists) { ret = ads_gen_add(ads, new_dn, mods); - else + } else { ret = ads_gen_mod(ads, new_dn, mods); + } - if (!ADS_ERR_OK(ret)) + if (!ADS_ERR_OK(ret)) { goto done; + } /* Do not fail if we can't set security descriptor * it shouldn't be mandatory and probably we just * don't have enough rights to do it. */ if (!exists) { - status = ads_set_machine_sd(ads, hostname, new_dn); + status = ads_set_machine_sd(ads, machine_name, new_dn); if (!ADS_ERR_OK(status)) { DEBUG(0, ("Warning: ads_set_machine_sd: %s\n", @@ -1087,6 +1367,7 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, } } done: + ads_msgfree(ads, res); talloc_destroy(ctx); return ret; } @@ -1303,47 +1584,50 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) * Join a machine to a realm * Creates the machine account and sets the machine password * @param ads connection to ads server - * @param hostname name of host to add + * @param machine name of host to add * @param org_unit Organizational unit to place machine in * @return status of join **/ -ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, +ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name, uint32 account_type, const char *org_unit) { ADS_STATUS status; - LDAPMessage *res; - char *host; + LDAPMessage *res = NULL; + char *machine; - /* hostname must be lowercase */ - host = strdup(hostname); - strlower_m(host); + /* machine name must be lowercase */ + machine = strdup(machine_name); + strlower_m(machine); /* - status = ads_find_machine_acct(ads, (void **)&res, host); + status = ads_find_machine_acct(ads, (void **)&res, machine); if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) { - DEBUG(0, ("Host account for %s already exists - deleting old account\n", host)); - status = ads_leave_realm(ads, host); + DEBUG(0, ("Host account for %s already exists - deleting old account\n", machine)); + status = ads_leave_realm(ads, machine); if (!ADS_ERR_OK(status)) { DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n", - host, ads->config.realm)); + machine, ads->config.realm)); return status; } } */ - status = ads_add_machine_acct(ads, host, account_type, org_unit); + status = ads_add_machine_acct(ads, machine, account_type, org_unit); if (!ADS_ERR_OK(status)) { - DEBUG(0, ("ads_add_machine_acct: %s\n", ads_errstr(status))); + DEBUG(0, ("ads_add_machine_acct (%s): %s\n", machine, ads_errstr(status))); + SAFE_FREE(machine); return status; } - status = ads_find_machine_acct(ads, (void **)&res, host); + status = ads_find_machine_acct(ads, (void **)&res, machine); if (!ADS_ERR_OK(status)) { - DEBUG(0, ("Host account test failed\n")); + DEBUG(0, ("Host account test failed for machine %s\n", machine)); + SAFE_FREE(machine); return status; } - free(host); + SAFE_FREE(machine); + ads_msgfree(ads, res); return status; } diff --git a/source/libads/sasl.c b/source/libads/sasl.c index 18cbb465887..8eb2c86bed5 100644 --- a/source/libads/sasl.c +++ b/source/libads/sasl.c @@ -201,14 +201,14 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { - DEBUG(3,("got OID=%s\n", OIDs[i])); + DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i])); if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || strcmp(OIDs[i], OID_KERBEROS5) == 0) { got_kerberos_mechanism = True; } free(OIDs[i]); } - DEBUG(3,("got principal=%s\n", principal)); + DEBUG(3,("ads_sasl_spnego_bind: got server principal name =%s\n", principal)); #ifdef HAVE_KRB5 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) && diff --git a/source/libsmb/asn1.c b/source/libsmb/asn1.c index ecc5e3dee64..ca14f3fbb71 100644 --- a/source/libsmb/asn1.c +++ b/source/libsmb/asn1.c @@ -320,17 +320,17 @@ int asn1_tag_remaining(ASN1_DATA *data) BOOL asn1_read_OID(ASN1_DATA *data, char **OID) { uint8 b; - pstring oid; + pstring oid_str; fstring el; if (!asn1_start_tag(data, ASN1_OID)) return False; asn1_read_uint8(data, &b); - oid[0] = 0; + oid_str[0] = 0; fstr_sprintf(el, "%u", b/40); - pstrcat(oid, el); + pstrcat(oid_str, el); fstr_sprintf(el, " %u", b%40); - pstrcat(oid, el); + pstrcat(oid_str, el); while (asn1_tag_remaining(data) > 0) { unsigned v = 0; @@ -339,12 +339,12 @@ BOOL asn1_read_OID(ASN1_DATA *data, char **OID) v = (v<<7) | (b&0x7f); } while (!data->has_error && b & 0x80); fstr_sprintf(el, " %u", v); - pstrcat(oid, el); + pstrcat(oid_str, el); } asn1_end_tag(data); - *OID = strdup(oid); + *OID = strdup(oid_str); return !data->has_error; } diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c index b75d6be0a60..281ee3af845 100644 --- a/source/libsmb/clientgen.c +++ b/source/libsmb/clientgen.c @@ -176,7 +176,12 @@ void cli_setup_packet(struct cli_state *cli) SSVAL(cli->outbuf,smb_mid,cli->mid); if (cli->protocol > PROTOCOL_CORE) { uint16 flags2; - SCVAL(cli->outbuf,smb_flg,0x8); + if (cli->case_sensitive) { + SCVAL(cli->outbuf,smb_flg,0x0); + } else { + /* Default setting, case insensitive. */ + SCVAL(cli->outbuf,smb_flg,0x8); + } flags2 = FLAGS2_LONG_PATH_COMPONENTS; if (cli->capabilities & CAP_UNICODE) flags2 |= FLAGS2_UNICODE_STRINGS; @@ -273,6 +278,7 @@ struct cli_state *cli_initialise(struct cli_state *cli) cli->outbuf = (char *)malloc(cli->bufsize+SAFETY_MARGIN); cli->inbuf = (char *)malloc(cli->bufsize+SAFETY_MARGIN); cli->oplock_handler = cli_oplock_ack; + cli->case_sensitive = False; cli->use_spnego = lp_client_use_spnego(); @@ -441,6 +447,17 @@ uint16 cli_setpid(struct cli_state *cli, uint16 pid) } /**************************************************************************** + Set the case sensitivity flag on the packets. Returns old state. +****************************************************************************/ + +BOOL cli_set_case_sensitive(struct cli_state *cli, BOOL case_sensitive) +{ + BOOL ret = cli->case_sensitive; + cli->case_sensitive = case_sensitive; + return ret; +} + +/**************************************************************************** Send a keepalive packet to the server ****************************************************************************/ BOOL cli_send_keepalive(struct cli_state *cli) diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c index 9027f192ef7..4929bd63ef2 100644 --- a/source/libsmb/clikrb5.c +++ b/source/libsmb/clikrb5.c @@ -124,13 +124,13 @@ #endif #if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES) -krb5_error_code get_kerberos_allowed_etypes(krb5_context context, + krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype **enctypes) { return krb5_get_permitted_enctypes(context, enctypes); } #elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES) -krb5_error_code get_kerberos_allowed_etypes(krb5_context context, + krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype **enctypes) { return krb5_get_default_in_tkt_etypes(context, enctypes); @@ -234,6 +234,13 @@ krb5_error_code get_kerberos_allowed_etypes(krb5_context context, } #endif +#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME) + void krb5_free_unparsed_name(krb5_context context, char *val) +{ + SAFE_FREE(val); +} +#endif + static BOOL ads_cleanup_expired_creds(krb5_context context, krb5_ccache ccache, krb5_creds *credsp) @@ -413,11 +420,12 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset, failed: if ( context ) { -#if 0 /* JERRY -- disabled since it causes heimdal 0.6.1rc3 to die - SuSE 9.1 Pro */ +/* Removed by jra. They really need to fix their kerberos so we don't leak memory. + JERRY -- disabled since it causes heimdal 0.6.1rc3 to die + SuSE 9.1 Pro +*/ if (ccdef) krb5_cc_close(context, ccdef); -#endif if (auth_context) krb5_auth_con_free(context, auth_context); krb5_free_context(context); @@ -465,6 +473,17 @@ failed: } #endif + krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry) +{ +#if defined(HAVE_KRB5_KT_FREE_ENTRY) + return krb5_kt_free_entry(context, kt_entry); +#elif defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS) + return krb5_free_keytab_entry_contents(context, kt_entry); +#else +#error UNKNOWN_KT_FREE_FUNCTION +#endif +} + #else /* HAVE_KRB5 */ /* this saves a few linking headaches */ int cli_krb5_get_ticket(const char *principal, time_t time_offset, diff --git a/source/libsmb/clispnego.c b/source/libsmb/clispnego.c index e6cadc466c1..85b7bd9e1ee 100644 --- a/source/libsmb/clispnego.c +++ b/source/libsmb/clispnego.c @@ -141,9 +141,9 @@ BOOL spnego_parse_negTokenInit(DATA_BLOB blob, asn1_start_tag(&data,ASN1_CONTEXT(0)); asn1_start_tag(&data,ASN1_SEQUENCE(0)); for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) { - char *oid = NULL; - asn1_read_OID(&data,&oid); - OIDs[i] = oid; + char *oid_str = NULL; + asn1_read_OID(&data,&oid_str); + OIDs[i] = oid_str; } OIDs[i] = NULL; asn1_end_tag(&data); @@ -230,9 +230,9 @@ BOOL parse_negTokenTarg(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], DATA_BLOB *se asn1_start_tag(&data, ASN1_CONTEXT(0)); asn1_start_tag(&data, ASN1_SEQUENCE(0)); for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) { - char *oid = NULL; - asn1_read_OID(&data,&oid); - OIDs[i] = oid; + char *oid_str = NULL; + asn1_read_OID(&data,&oid_str); + OIDs[i] = oid_str; } OIDs[i] = NULL; asn1_end_tag(&data); diff --git a/source/libsmb/conncache.c b/source/libsmb/conncache.c index e6604617d68..15cc75b129e 100644 --- a/source/libsmb/conncache.c +++ b/source/libsmb/conncache.c @@ -154,5 +154,3 @@ void flush_negative_conn_cache( void ) } } - - diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c index 2bb7359e742..cee0015e257 100644 --- a/source/libsmb/namequery.c +++ b/source/libsmb/namequery.c @@ -56,7 +56,8 @@ static struct node_status *parse_node_status(char *p, int *num_names, struct nod return NULL; ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names)); - if (!ret) return NULL; + if (!ret) + return NULL; p++; for (i=0;i< *num_names;i++) { @@ -556,84 +557,80 @@ XFILE *startlmhosts(char *fname) BOOL getlmhostsent( XFILE *fp, pstring name, int *name_type, struct in_addr *ipaddr) { - pstring line; - - while(!x_feof(fp) && !x_ferror(fp)) { - pstring ip,flags,extra; - const char *ptr; - char *ptr1; - int count = 0; + pstring line; - *name_type = -1; + while(!x_feof(fp) && !x_ferror(fp)) { + pstring ip,flags,extra; + const char *ptr; + char *ptr1; + int count = 0; - if (!fgets_slash(line,sizeof(pstring),fp)) - continue; + *name_type = -1; - if (*line == '#') - continue; + if (!fgets_slash(line,sizeof(pstring),fp)) { + continue; + } - pstrcpy(ip,""); - pstrcpy(name,""); - pstrcpy(flags,""); + if (*line == '#') { + continue; + } - ptr = line; + pstrcpy(ip,""); + pstrcpy(name,""); + pstrcpy(flags,""); - if (next_token(&ptr,ip ,NULL,sizeof(ip))) - ++count; - if (next_token(&ptr,name ,NULL, sizeof(pstring))) - ++count; - if (next_token(&ptr,flags,NULL, sizeof(flags))) - ++count; - if (next_token(&ptr,extra,NULL, sizeof(extra))) - ++count; + ptr = line; - if (count <= 0) - continue; + if (next_token(&ptr,ip ,NULL,sizeof(ip))) + ++count; + if (next_token(&ptr,name ,NULL, sizeof(pstring))) + ++count; + if (next_token(&ptr,flags,NULL, sizeof(flags))) + ++count; + if (next_token(&ptr,extra,NULL, sizeof(extra))) + ++count; - if (count > 0 && count < 2) - { - DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line)); - continue; - } + if (count <= 0) + continue; - if (count >= 4) - { - DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n")); - continue; - } + if (count > 0 && count < 2) { + DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line)); + continue; + } - DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags)); + if (count >= 4) { + DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n")); + continue; + } - if (strchr_m(flags,'G') || strchr_m(flags,'S')) - { - DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n")); - continue; - } + DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags)); - *ipaddr = *interpret_addr2(ip); + if (strchr_m(flags,'G') || strchr_m(flags,'S')) { + DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n")); + continue; + } - /* Extra feature. If the name ends in '#XX', where XX is a hex number, - then only add that name type. */ - if((ptr1 = strchr_m(name, '#')) != NULL) - { - char *endptr; + *ipaddr = *interpret_addr2(ip); - ptr1++; - *name_type = (int)strtol(ptr1, &endptr, 16); + /* Extra feature. If the name ends in '#XX', where XX is a hex number, + then only add that name type. */ + if((ptr1 = strchr_m(name, '#')) != NULL) { + char *endptr; + ptr1++; - if(!*ptr1 || (endptr == ptr1)) - { - DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name)); - continue; - } + *name_type = (int)strtol(ptr1, &endptr, 16); + if(!*ptr1 || (endptr == ptr1)) { + DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name)); + continue; + } - *(--ptr1) = '\0'; /* Truncate at the '#' */ - } + *(--ptr1) = '\0'; /* Truncate at the '#' */ + } - return True; - } + return True; + } - return False; + return False; } /******************************************************** @@ -998,145 +995,145 @@ static BOOL internal_resolve_name(const char *name, int name_type, struct ip_service **return_iplist, int *return_count, const char *resolve_order) { - pstring name_resolve_list; - fstring tok; - const char *ptr; - BOOL allones = (strcmp(name,"255.255.255.255") == 0); - BOOL allzeros = (strcmp(name,"0.0.0.0") == 0); - BOOL is_address = is_ipaddress(name); - BOOL result = False; - int i; + pstring name_resolve_list; + fstring tok; + const char *ptr; + BOOL allones = (strcmp(name,"255.255.255.255") == 0); + BOOL allzeros = (strcmp(name,"0.0.0.0") == 0); + BOOL is_address = is_ipaddress(name); + BOOL result = False; + int i; - *return_iplist = NULL; - *return_count = 0; + *return_iplist = NULL; + *return_count = 0; - DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type)); + DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type)); - if (allzeros || allones || is_address) { + if (allzeros || allones || is_address) { - if ( (*return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service))) == NULL ) { - DEBUG(0,("internal_resolve_name: malloc fail !\n")); - return False; - } + if ( (*return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service))) == NULL ) { + DEBUG(0,("internal_resolve_name: malloc fail !\n")); + return False; + } - if(is_address) { - /* ignore the port here */ - (*return_iplist)->port = PORT_NONE; + if(is_address) { + /* ignore the port here */ + (*return_iplist)->port = PORT_NONE; - /* if it's in the form of an IP address then get the lib to interpret it */ - if (((*return_iplist)->ip.s_addr = inet_addr(name)) == 0xFFFFFFFF ){ - DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name)); - return False; + /* if it's in the form of an IP address then get the lib to interpret it */ + if (((*return_iplist)->ip.s_addr = inet_addr(name)) == 0xFFFFFFFF ){ + DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name)); + return False; + } + } else { + (*return_iplist)->ip.s_addr = allones ? 0xFFFFFFFF : 0; } - } else { - (*return_iplist)->ip.s_addr = allones ? 0xFFFFFFFF : 0; + *return_count = 1; + return True; } - *return_count = 1; - return True; - } - /* Check name cache */ + /* Check name cache */ - if (namecache_fetch(name, name_type, return_iplist, return_count)) { - /* This could be a negative response */ - return (*return_count > 0); - } + if (namecache_fetch(name, name_type, return_iplist, return_count)) { + /* This could be a negative response */ + return (*return_count > 0); + } - /* set the name resolution order */ + /* set the name resolution order */ - if ( strcmp( resolve_order, "NULL") == 0 ) { - DEBUG(8,("internal_resolve_name: all lookups disabled\n")); - return False; - } - - if ( !resolve_order ) - pstrcpy(name_resolve_list, lp_name_resolve_order()); - else - pstrcpy(name_resolve_list, resolve_order); + if ( strcmp( resolve_order, "NULL") == 0 ) { + DEBUG(8,("internal_resolve_name: all lookups disabled\n")); + return False; + } - if ( !name_resolve_list[0] ) - ptr = "host"; - else - ptr = name_resolve_list; + if ( !resolve_order ) { + pstrcpy(name_resolve_list, lp_name_resolve_order()); + } else { + pstrcpy(name_resolve_list, resolve_order); + + if ( !name_resolve_list[0] ) { + ptr = "host"; + } else { + ptr = name_resolve_list; + } - /* iterate through the name resolution backends */ + /* iterate through the name resolution backends */ - while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) { - if((strequal(tok, "host") || strequal(tok, "hosts"))) { - if (resolve_hosts(name, name_type, return_iplist, return_count)) { - result = True; - goto done; - } - } else if(strequal( tok, "ads")) { - /* deal with 0x1c names here. This will result in a - SRV record lookup for _ldap._tcp. if we - are using 'security = ads' */ - if (resolve_ads(name, name_type, return_iplist, return_count)) { - result = True; - goto done; - } - } else if(strequal( tok, "lmhosts")) { - if (resolve_lmhosts(name, name_type, return_iplist, return_count)) { - result = True; - goto done; - } - } else if(strequal( tok, "wins")) { - /* don't resolve 1D via WINS */ - if (name_type != 0x1D && - resolve_wins(name, name_type, return_iplist, return_count)) { - result = True; - goto done; - } - } else if(strequal( tok, "bcast")) { - if (name_resolve_bcast(name, name_type, return_iplist, return_count)) { - result = True; - goto done; - } - } else { - DEBUG(0,("resolve_name: unknown name switch type %s\n", tok)); - } - } - - /* All of the resolve_* functions above have returned false. */ - - SAFE_FREE(*return_iplist); - *return_count = 0; - - return False; + while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) { + if((strequal(tok, "host") || strequal(tok, "hosts"))) { + if (resolve_hosts(name, name_type, return_iplist, return_count)) { + result = True; + goto done; + } + } else if(strequal( tok, "ads")) { + /* deal with 0x1c names here. This will result in a + SRV record lookup for _ldap._tcp. if we + are using 'security = ads' */ + if (resolve_ads(name, name_type, return_iplist, return_count)) { + result = True; + goto done; + } + } else if(strequal( tok, "lmhosts")) { + if (resolve_lmhosts(name, name_type, return_iplist, return_count)) { + result = True; + goto done; + } + } else if(strequal( tok, "wins")) { + /* don't resolve 1D via WINS */ + if (name_type != 0x1D && resolve_wins(name, name_type, return_iplist, return_count)) { + result = True; + goto done; + } + } else if(strequal( tok, "bcast")) { + if (name_resolve_bcast(name, name_type, return_iplist, return_count)) { + result = True; + goto done; + } + } else { + DEBUG(0,("resolve_name: unknown name switch type %s\n", tok)); + } + } - done: + /* All of the resolve_* functions above have returned false. */ + + SAFE_FREE(*return_iplist); + *return_count = 0; + + return False; - /* Remove duplicate entries. Some queries, notably #1c (domain - controllers) return the PDC in iplist[0] and then all domain - controllers including the PDC in iplist[1..n]. Iterating over - the iplist when the PDC is down will cause two sets of timeouts. */ + done: - if ( *return_count ) { - *return_count = remove_duplicate_addrs2( *return_iplist, *return_count ); - } + /* Remove duplicate entries. Some queries, notably #1c (domain + controllers) return the PDC in iplist[0] and then all domain + controllers including the PDC in iplist[1..n]. Iterating over + the iplist when the PDC is down will cause two sets of timeouts. */ + + if ( *return_count ) { + *return_count = remove_duplicate_addrs2( *return_iplist, *return_count ); + } - /* Save in name cache */ - if ( DEBUGLEVEL >= 100 ) { - for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++) - DEBUG(100, ("Storing name %s of type %d (%s:%d)\n", name, - name_type, inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port)); - } + /* Save in name cache */ + if ( DEBUGLEVEL >= 100 ) { + for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++) + DEBUG(100, ("Storing name %s of type %d (%s:%d)\n", name, + name_type, inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port)); + } - namecache_store(name, name_type, *return_count, *return_iplist); - - /* Display some debugging info */ + namecache_store(name, name_type, *return_count, *return_iplist); - if ( DEBUGLEVEL >= 10 ) { - DEBUG(10, ("internal_resolve_name: returning %d addresses: ", - *return_count)); + /* Display some debugging info */ - for (i = 0; i < *return_count; i++) - DEBUGADD(10, ("%s:%d ", inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port)); + if ( DEBUGLEVEL >= 10 ) { + DEBUG(10, ("internal_resolve_name: returning %d addresses: ", *return_count)); - DEBUG(10, ("\n")); - } + for (i = 0; i < *return_count; i++) { + DEBUGADD(10, ("%s:%d ", inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port)); + } + DEBUG(10, ("\n")); + } + } - return result; + return result; } /******************************************************** @@ -1218,8 +1215,9 @@ BOOL get_pdc_ip(const char *domain, struct in_addr *ip) /* Look up #1B name */ - if (!internal_resolve_name(domain, 0x1b, &ip_list, &count, lp_name_resolve_order())) + if (!internal_resolve_name(domain, 0x1b, &ip_list, &count, lp_name_resolve_order())) { return False; + } /* if we get more than 1 IP back we have to assume it is a multi-homed PDC and not a mess up */ @@ -1298,16 +1296,17 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list, num_addresses += auto_count; done_auto_lookup = True; DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count)); - } - else + } else { num_addresses++; + } } /* if we have no addresses and haven't done the auto lookup, then just return the list of DC's */ - if ( (num_addresses == 0) && !done_auto_lookup ) + if ( (num_addresses == 0) && !done_auto_lookup ) { return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order); + } /* maybe we just failed? */ @@ -1317,8 +1316,7 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list, } if ( (return_iplist = (struct ip_service *) - malloc(num_addresses * sizeof(struct ip_service))) == NULL ) - { + malloc(num_addresses * sizeof(struct ip_service))) == NULL ) { DEBUG(3,("get_dc_list: malloc fail !\n")); return False; } @@ -1335,6 +1333,13 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list, if ( strequal(name, "*") ) { for ( j=0; j= 4 ) { DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count, @@ -1392,8 +1405,9 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list, } /********************************************************************* - small wrapper function to get the DC list and sort it if neccessary + Small wrapper function to get the DC list and sort it if neccessary. *********************************************************************/ + BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *count, BOOL ads_only ) { BOOL ordered; @@ -1401,13 +1415,14 @@ BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *c DEBUG(8,("get_sorted_dc_list: attempting lookup using [%s]\n", (ads_only ? "ads" : lp_name_resolve_order()))); - if ( !get_dc_list(domain, ip_list, count, ads_only, &ordered) ) - return False; + if ( !get_dc_list(domain, ip_list, count, ads_only, &ordered) ) { + return False; + } /* only sort if we don't already have an ordered list */ - if ( !ordered ) + if ( !ordered ) { sort_ip_list2( *ip_list, *count ); + } return True; } - diff --git a/source/libsmb/ntlmssp.c b/source/libsmb/ntlmssp.c index 52e5cd004ff..66d48afc463 100644 --- a/source/libsmb/ntlmssp.c +++ b/source/libsmb/ntlmssp.c @@ -1102,8 +1102,6 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state) NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_NTLM2 | NTLMSSP_NEGOTIATE_KEY_EXCH | - NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED | - NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED | /* * We need to set this to allow a later SetPassword * via the SAMR pipe to succeed. Strange.... We could diff --git a/source/libsmb/smb_signing.c b/source/libsmb/smb_signing.c index 7130453c0c9..8c59e49ebb9 100644 --- a/source/libsmb/smb_signing.c +++ b/source/libsmb/smb_signing.c @@ -42,11 +42,18 @@ struct smb_basic_signing_context { struct outstanding_packet_lookup *outstanding_packet_list; }; -static void store_sequence_for_reply(struct outstanding_packet_lookup **list, +static BOOL store_sequence_for_reply(struct outstanding_packet_lookup **list, uint16 mid, uint32 reply_seq_num) { struct outstanding_packet_lookup *t; + /* Ensure we only add a mid once. */ + for (t = *list; t; t = t->next) { + if (t->mid == mid) { + return False; + } + } + t = smb_xmalloc(sizeof(*t)); ZERO_STRUCTP(t); @@ -65,6 +72,7 @@ static void store_sequence_for_reply(struct outstanding_packet_lookup **list, DLIST_ADD(*list, t); DEBUG(10,("store_sequence_for_reply: stored seq = %u mid = %u\n", (unsigned int)reply_seq_num, (unsigned int)mid )); + return True; } static BOOL get_sequence_for_reply(struct outstanding_packet_lookup **list, @@ -489,6 +497,7 @@ BOOL cli_simple_set_signing(struct cli_state *cli, void cli_signing_trans_start(struct cli_state *cli, uint16 mid) { struct smb_basic_signing_context *data = cli->sign_info.signing_context; + uint32 reply_seq_num; if (!cli->sign_info.doing_signing || !data) return; @@ -496,9 +505,16 @@ void cli_signing_trans_start(struct cli_state *cli, uint16 mid) data->trans_info = smb_xmalloc(sizeof(struct trans_info_context)); ZERO_STRUCTP(data->trans_info); - data->trans_info->send_seq_num = data->send_seq_num-2; + /* This ensures the sequence is pulled off the outstanding packet list */ + if (!get_sequence_for_reply(&data->outstanding_packet_list, + mid, &reply_seq_num)) { + DEBUG(1, ("get_sequence_for_reply failed - did we enter the trans signing state without sending a packet?\n")); + return; + } + + data->trans_info->send_seq_num = reply_seq_num - 1; data->trans_info->mid = mid; - data->trans_info->reply_seq_num = data->send_seq_num-1; + data->trans_info->reply_seq_num = reply_seq_num; DEBUG(10,("cli_signing_trans_start: storing mid = %u, reply_seq_num = %u, send_seq_num = %u \ data->send_seq_num = %u\n", @@ -748,14 +764,16 @@ static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si, BO if (!good) { - DEBUG(5, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n", - (unsigned int)saved_seq)); - dump_data(5, (const char *)calc_md5_mac, 8); - - DEBUG(5, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n", + if (saved_seq) { + DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n", (unsigned int)saved_seq)); - dump_data(5, (const char *)server_sent_mac, 8); + dump_data(5, (const char *)calc_md5_mac, 8); + DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n", + (unsigned int)reply_seq_number)); + dump_data(5, (const char *)server_sent_mac, 8); + } + #if 1 /* JRATEST */ { int i; @@ -848,9 +866,13 @@ void srv_defer_sign_response(uint16 mid) if (!data) return; - store_sequence_for_reply(&data->outstanding_packet_list, - mid, data->send_seq_num); - data->send_seq_num++; + /* + * Ensure we only store this mid reply once... + */ + + if (store_sequence_for_reply(&data->outstanding_packet_list, mid, data->send_seq_num)) { + data->send_seq_num++; + } } /*********************************************************** diff --git a/source/locking/brlock.c b/source/locking/brlock.c index 47001c8b89c..990a6a25d2f 100644 --- a/source/locking/brlock.c +++ b/source/locking/brlock.c @@ -246,8 +246,8 @@ void brl_init(int read_only) { if (tdb) return; - tdb = tdb_open_ex(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST), - read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644, smbd_tdb_log); + tdb = tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST), + read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 ); if (!tdb) { DEBUG(0,("Failed to open byte range locking database\n")); return; diff --git a/source/locking/locking.c b/source/locking/locking.c index 42036cc70cf..8f53b55fc54 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -40,6 +40,17 @@ uint16 global_smbpid; /* the locking database handle */ static TDB_CONTEXT *tdb; +struct locking_data { + union { + int num_share_mode_entries; + share_mode_entry dummy; /* Needed for alignment. */ + } u; + /* the following two entries are implicit + share_mode_entry modes[num_share_mode_entries]; + char file_name[]; + */ +}; + /**************************************************************************** Debugging aid :-). ****************************************************************************/ @@ -283,10 +294,10 @@ BOOL locking_init(int read_only) if (tdb) return True; - tdb = tdb_open_ex(lock_path("locking.tdb"), + tdb = tdb_open_log(lock_path("locking.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST), read_only?O_RDONLY:O_RDWR|O_CREAT, - 0644, smbd_tdb_log); + 0644); if (!tdb) { DEBUG(0,("ERROR: Failed to initialise locking database\n")); @@ -432,6 +443,7 @@ int get_share_modes(connection_struct *conn, data = (struct locking_data *)dbuf.dptr; num_share_modes = data->u.num_share_mode_entries; if(num_share_modes) { + pstring fname; int i; int del_count = 0; @@ -443,6 +455,9 @@ int get_share_modes(connection_struct *conn, return 0; } + /* Save off the associated filename. */ + pstrcpy(fname, dbuf.dptr + sizeof(*data) + num_share_modes * sizeof(share_mode_entry)); + /* * Ensure that each entry has a real process attached. */ @@ -454,8 +469,10 @@ int get_share_modes(connection_struct *conn, i++; } else { DEBUG(10,("get_share_modes: deleted %s\n", share_mode_str(i, entry_p) )); - memcpy( &shares[i], &shares[i+1], - sizeof(share_mode_entry) * (num_share_modes - i - 1)); + if (num_share_modes - i - 1 > 0) { + memcpy( &shares[i], &shares[i+1], + sizeof(share_mode_entry) * (num_share_modes - i - 1)); + } num_share_modes--; del_count++; } @@ -465,17 +482,28 @@ int get_share_modes(connection_struct *conn, if (del_count) { data->u.num_share_mode_entries = num_share_modes; - if (num_share_modes) + if (num_share_modes) { memcpy(dbuf.dptr + sizeof(*data), shares, num_share_modes * sizeof(share_mode_entry)); + /* Append the filename. */ + pstrcpy(dbuf.dptr + sizeof(*data) + num_share_modes * sizeof(share_mode_entry), fname); + } /* The record has shrunk a bit */ dbuf.dsize -= del_count * sizeof(share_mode_entry); - if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) { - SAFE_FREE(shares); - SAFE_FREE(dbuf.dptr); - return 0; + if (data->u.num_share_mode_entries == 0) { + if (tdb_delete(tdb, key) == -1) { + SAFE_FREE(shares); + SAFE_FREE(dbuf.dptr); + return 0; + } + } else { + if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) { + SAFE_FREE(shares); + SAFE_FREE(dbuf.dptr); + return 0; + } } } } @@ -575,8 +603,10 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, if (ppse) *ppse = memdup(&shares[i], sizeof(*shares)); data->u.num_share_mode_entries--; - memmove(&shares[i], &shares[i+1], - dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))); + if ((dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))) > 0) { + memmove(&shares[i], &shares[i+1], + dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))); + } del_count++; DEBUG(10,("del_share_entry: deleting entry %d\n", i )); @@ -843,6 +873,358 @@ BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close) return True; } +/******************************************************************* + Print out a deferred open entry. +********************************************************************/ + +char *deferred_open_str(int num, deferred_open_entry *e) +{ + static pstring de_str; + + slprintf(de_str, sizeof(de_str)-1, "deferred_open_entry[%d]: \ +pid = %lu, mid = %u, dev = 0x%x, inode = %.0f, port = %u, time = [%u.%06u]", + num, (unsigned long)e->pid, (unsigned int)e->mid, (unsigned int)e->dev, (double)e->inode, + (unsigned int)e->port, + (unsigned int)e->time.tv_sec, (unsigned int)e->time.tv_usec ); + + return de_str; +} + +/* Internal data structures for deferred opens... */ + +struct de_locking_key { + char name[4]; + SMB_DEV_T dev; + SMB_INO_T inode; +}; + +struct deferred_open_data { + union { + int num_deferred_open_entries; + deferred_open_entry dummy; /* Needed for alignment. */ + } u; + /* the following two entries are implicit + deferred_open_entry de_entries[num_deferred_open_entries]; + char file_name[]; + */ +}; + +/******************************************************************* + Print out a deferred open table. +********************************************************************/ + +static void print_deferred_open_table(struct deferred_open_data *data) +{ + int num_de_entries = data->u.num_deferred_open_entries; + deferred_open_entry *de_entries = (deferred_open_entry *)(data + 1); + int i; + + for (i = 0; i < num_de_entries; i++) { + deferred_open_entry *entry_p = &de_entries[i]; + DEBUG(10,("print_deferred_open_table: %s\n", deferred_open_str(i, entry_p) )); + } +} + + +/******************************************************************* + Form a static deferred open locking key for a dev/inode pair. +******************************************************************/ + +static TDB_DATA deferred_open_locking_key(SMB_DEV_T dev, SMB_INO_T inode) +{ + static struct de_locking_key key; + TDB_DATA kbuf; + + memset(&key, '\0', sizeof(key)); + memcpy(&key.name[0], "DOE", 4); + key.dev = dev; + key.inode = inode; + kbuf.dptr = (char *)&key; + kbuf.dsize = sizeof(key); + return kbuf; +} + +/******************************************************************* + Get all deferred open entries for a dev/inode pair. +********************************************************************/ + +int get_deferred_opens(connection_struct *conn, + SMB_DEV_T dev, SMB_INO_T inode, + deferred_open_entry **pp_de_entries) +{ + TDB_DATA dbuf; + struct deferred_open_data *data; + int num_de_entries; + deferred_open_entry *de_entries = NULL; + TDB_DATA key = deferred_open_locking_key(dev, inode); + + *pp_de_entries = NULL; + + dbuf = tdb_fetch(tdb, key); + if (!dbuf.dptr) + return 0; + + data = (struct deferred_open_data *)dbuf.dptr; + num_de_entries = data->u.num_deferred_open_entries; + if(num_de_entries) { + pstring fname; + int i; + int del_count = 0; + + de_entries = (deferred_open_entry *)memdup(dbuf.dptr + sizeof(*data), + num_de_entries * sizeof(deferred_open_entry)); + + if (!de_entries) { + SAFE_FREE(dbuf.dptr); + return 0; + } + + /* Save off the associated filename. */ + pstrcpy(fname, dbuf.dptr + sizeof(*data) + num_de_entries * sizeof(deferred_open_entry)); + + /* + * Ensure that each entry has a real process attached. + */ + + for (i = 0; i < num_de_entries; ) { + deferred_open_entry *entry_p = &de_entries[i]; + if (process_exists(entry_p->pid)) { + DEBUG(10,("get_deferred_opens: %s\n", deferred_open_str(i, entry_p) )); + i++; + } else { + DEBUG(10,("get_deferred_opens: deleted %s\n", deferred_open_str(i, entry_p) )); + if (num_de_entries - i - 1 > 0) { + memcpy( &de_entries[i], &de_entries[i+1], + sizeof(deferred_open_entry) * (num_de_entries - i - 1)); + } + num_de_entries--; + del_count++; + } + } + + /* Did we delete any ? If so, re-store in tdb. */ + if (del_count) { + data->u.num_deferred_open_entries = num_de_entries; + + if (num_de_entries) { + memcpy(dbuf.dptr + sizeof(*data), de_entries, + num_de_entries * sizeof(deferred_open_entry)); + /* Append the filename. */ + pstrcpy(dbuf.dptr + sizeof(*data) + num_de_entries * sizeof(deferred_open_entry), fname); + } + + /* The record has shrunk a bit */ + dbuf.dsize -= del_count * sizeof(deferred_open_entry); + + if (data->u.num_deferred_open_entries == 0) { + if (tdb_delete(tdb, key) == -1) { + SAFE_FREE(de_entries); + SAFE_FREE(dbuf.dptr); + return 0; + } + } else { + if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) { + SAFE_FREE(de_entries); + SAFE_FREE(dbuf.dptr); + return 0; + } + } + } + } + + SAFE_FREE(dbuf.dptr); + *pp_de_entries = de_entries; + return num_de_entries; +} + +/******************************************************************* + Check if two deferred open entries are identical. +********************************************************************/ + +static BOOL deferred_open_entries_identical( deferred_open_entry *e1, deferred_open_entry *e2) +{ +#if 1 /* JRA PARANOIA TEST - REMOVE LATER */ + if (e1->pid == e2->pid && + e1->port == e2->port && + e1->dev == e2->dev && + e1->inode == e2->inode && + ((e1->time.tv_sec != e2->time.tv_sec) || + (e1->time.tv_usec != e2->time.tv_usec) || + (e1->mid != e2->mid))) { + smb_panic("PANIC: deferred_open_entries_identical: logic error.\n"); + } +#endif + + return (e1->pid == e2->pid && + e1->mid == e2->mid && + e1->port == e2->port && + e1->dev == e2->dev && + e1->inode == e2->inode && + e1->time.tv_sec == e2->time.tv_sec && + e1->time.tv_usec == e2->time.tv_usec); +} + + +/******************************************************************* + Delete a specific deferred open entry. + Ignore if no entry deleted. +********************************************************************/ + +BOOL delete_deferred_open_entry(deferred_open_entry *entry) +{ + TDB_DATA dbuf; + struct deferred_open_data *data; + int i, del_count=0; + deferred_open_entry *de_entries; + BOOL ret = True; + TDB_DATA key = deferred_open_locking_key(entry->dev, entry->inode); + + /* read in the existing share modes */ + dbuf = tdb_fetch(tdb, key); + if (!dbuf.dptr) + return -1; + + data = (struct deferred_open_data *)dbuf.dptr; + de_entries = (deferred_open_entry *)(dbuf.dptr + sizeof(*data)); + + /* + * Find any with this pid and delete it + * by overwriting with the rest of the data + * from the record. + */ + + DEBUG(10,("delete_deferred_open_entry: num_deferred_open_entries = %d\n", + data->u.num_deferred_open_entries )); + + for (i=0;iu.num_deferred_open_entries;) { + if (deferred_open_entries_identical(&de_entries[i], entry)) { + DEBUG(10,("delete_deferred_open_entry: deleted %s\n", + deferred_open_str(i, &de_entries[i]) )); + + data->u.num_deferred_open_entries--; + if ((dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*de_entries))) > 0) { + memmove(&de_entries[i], &de_entries[i+1], + dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*de_entries))); + } + del_count++; + + DEBUG(10,("delete_deferred_open_entry: deleting entry %d\n", i )); + + } else { + i++; + } + } + + SMB_ASSERT(del_count == 0 || del_count == 1); + + if (del_count) { + /* the record may have shrunk a bit */ + dbuf.dsize -= del_count * sizeof(*de_entries); + + /* store it back in the database */ + if (data->u.num_deferred_open_entries == 0) { + if (tdb_delete(tdb, key) == -1) + ret = False; + } else { + if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) + ret = False; + } + } + DEBUG(10,("delete_deferred_open_entry: Remaining table.\n")); + print_deferred_open_table((struct deferred_open_data*)dbuf.dptr); + SAFE_FREE(dbuf.dptr); + return ret; +} + +/******************************************************************* + Fill a deferred open entry. +********************************************************************/ + +static void fill_deferred_open(char *p, uint16 mid, struct timeval *ptv, SMB_DEV_T dev, SMB_INO_T inode, uint16 port) +{ + deferred_open_entry *e = (deferred_open_entry *)p; + void *x = &e->time; /* Needed to force alignment. p may not be aligned.... */ + + memset(e, '\0', sizeof(deferred_open_entry)); + e->mid = mid; + e->pid = sys_getpid(); + memcpy(x, ptv, sizeof(struct timeval)); + e->dev = dev; + e->inode = inode; + e->port = port; +} + +/******************************************************************* + Add a deferred open record. Return False on fail, True on success. +********************************************************************/ + +BOOL add_deferred_open(uint16 mid, struct timeval *ptv, SMB_DEV_T dev, SMB_INO_T inode, uint16 port, const char *fname) +{ + TDB_DATA dbuf; + struct deferred_open_data *data; + char *p=NULL; + int size; + TDB_DATA key = deferred_open_locking_key(dev, inode); + BOOL ret = True; + + /* read in the existing deferred open records if any */ + dbuf = tdb_fetch(tdb, key); + if (!dbuf.dptr) { + size_t offset; + /* we'll need to create a new record */ + + size = sizeof(*data) + sizeof(deferred_open_entry) + strlen(fname) + 1; + p = (char *)malloc(size); + if (!p) + return False; + data = (struct deferred_open_data *)p; + data->u.num_deferred_open_entries = 1; + + DEBUG(10,("add_deferred_open: creating entry for file %s. num_deferred_open_entries = 1\n", + fname )); + + offset = sizeof(*data) + sizeof(deferred_open_entry); + safe_strcpy(p + offset, fname, size - offset - 1); + fill_deferred_open(p + sizeof(*data), mid, ptv, dev, inode, port); + dbuf.dptr = p; + dbuf.dsize = size; + if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) + ret = False; + + print_deferred_open_table((struct deferred_open_data *)p); + + SAFE_FREE(p); + return ret; + } + + /* we're adding to an existing entry - this is a bit fiddly */ + data = (struct deferred_open_data *)dbuf.dptr; + + data->u.num_deferred_open_entries++; + + DEBUG(10,("add_deferred_open: adding entry for file %s. new num_deferred_open_entries = %d\n", + fname, data->u.num_deferred_open_entries )); + + size = dbuf.dsize + sizeof(deferred_open_entry); + p = malloc(size); + if (!p) { + SAFE_FREE(dbuf.dptr); + return False; + } + memcpy(p, dbuf.dptr, sizeof(*data)); + fill_deferred_open(p + sizeof(*data), mid, ptv, dev, inode, port); + memcpy(p + sizeof(*data) + sizeof(deferred_open_entry), dbuf.dptr + sizeof(*data), + dbuf.dsize - sizeof(*data)); + SAFE_FREE(dbuf.dptr); + dbuf.dptr = p; + dbuf.dsize = size; + if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) + ret = False; + print_deferred_open_table((struct deferred_open_data *)p); + SAFE_FREE(p); + return ret; +} + /**************************************************************************** Traverse the whole database with this function, calling traverse_callback on each share mode @@ -858,6 +1240,10 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, SHAREMODE_FN(traverse_callback) = (SHAREMODE_FN_CAST())state; + /* Ensure this is a locking_key record. */ + if (kbuf.dsize != sizeof(struct locking_key)) + return 0; + data = (struct locking_data *)dbuf.dptr; shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); name = dbuf.dptr + sizeof(*data) + data->u.num_share_mode_entries*sizeof(*shares); diff --git a/source/nmbd/nmbd_browsesync.c b/source/nmbd/nmbd_browsesync.c index 15827e21bae..56ffdc2670f 100644 --- a/source/nmbd/nmbd_browsesync.c +++ b/source/nmbd/nmbd_browsesync.c @@ -103,6 +103,7 @@ static void announce_local_master_browser_to_domain_master_browser( struct work_ { pstring outbuf; unstring myname; + unstring dmb_name; char *p; if(ismyip(work->dmb_addr)) { @@ -135,8 +136,10 @@ static void announce_local_master_browser_to_domain_master_browser( struct work_ work->work_group ); } + /* Target name for send_mailslot must be in UNIX charset. */ + pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name); send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf), - global_myname(), 0x0, work->dmb_name.name, 0x0, + global_myname(), 0x0, dmb_name, 0x0, work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT); } diff --git a/source/nmbd/nmbd_winsserver.c b/source/nmbd/nmbd_winsserver.c index 582338d710a..0e0289d9a33 100644 --- a/source/nmbd/nmbd_winsserver.c +++ b/source/nmbd/nmbd_winsserver.c @@ -1727,11 +1727,16 @@ void initiate_wins_processing(time_t t) && (namerec->data.death_time < t) ) { if( namerec->data.source == SELF_NAME ) { - DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF name %s\n", + DEBUG( 3, ( "initiate_wins_processing: Subnet %s not expiring SELF name %s\n", wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) ); namerec->data.death_time += 300; namerec->subnet->namelist_changed = True; continue; + } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) { + DEBUG(3,("initiate_wins_processing: deleting timed out DNS name %s\n", + nmb_namestr(&namerec->name))); + remove_name_from_namelist( wins_server_subnet, namerec ); + continue; } /* handle records, samba is the wins owner */ diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c index a98bd294064..50b6f0a87fb 100644 --- a/source/nsswitch/winbindd.c +++ b/source/nsswitch/winbindd.c @@ -869,16 +869,13 @@ int main(int argc, char **argv) ZERO_STRUCT(server_state); - if (!winbindd_param_init()) - return 1; - /* Winbind daemon initialisation */ - if (!winbindd_upgrade_idmap()) - return 1; - - if (!idmap_init(lp_idmap_backend())) - return 1; + if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) || + (!idmap_init(lp_idmap_backend())) ) { + DEBUG(1, ("Could not init idmap -- netlogon proxy only\n")); + idmap_proxyonly(); + } generate_wellknown_sids(); diff --git a/source/nsswitch/winbindd_cache.c b/source/nsswitch/winbindd_cache.c index 877fa2d995c..bbd98a620f6 100644 --- a/source/nsswitch/winbindd_cache.c +++ b/source/nsswitch/winbindd_cache.c @@ -363,6 +363,12 @@ static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force) if ( NT_STATUS_IS_OK(status) ) goto done; + /* important! make sure that we know if this is a native + mode domain or not */ + + if ( !domain->initialized ) + set_dc_type_and_flags( domain ); + status = domain->backend->sequence_number(domain, &domain->sequence_number); if (!NT_STATUS_IS_OK(status)) { diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c index eda962088d4..04f87fc1a2f 100644 --- a/source/nsswitch/winbindd_cm.c +++ b/source/nsswitch/winbindd_cm.c @@ -117,21 +117,40 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password) /* setup for schannel on any pipes opened on this connection */ -static NTSTATUS setup_schannel(struct cli_state *cli) +static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain ) { NTSTATUS ret; uchar trust_password[16]; uint32 sec_channel_type; + DOM_SID sid; + time_t lct; - if (!secrets_fetch_trust_account_password(lp_workgroup(), - trust_password, - NULL, &sec_channel_type)) { - return NT_STATUS_UNSUCCESSFUL; + /* use the domain trust password if we're on a DC + and this is not our domain */ + + if ( IS_DC && !strequal(domain, lp_workgroup()) ) { + char *pass = NULL; + + if ( !secrets_fetch_trusted_domain_password( domain, + &pass, &sid, &lct) ) + { + return NT_STATUS_UNSUCCESSFUL; + } + + sec_channel_type = SEC_CHAN_DOMAIN; + E_md4hash(pass, trust_password); + SAFE_FREE( pass ); + + } else { + if (!secrets_fetch_trust_account_password(lp_workgroup(), + trust_password, NULL, &sec_channel_type)) + { + return NT_STATUS_UNSUCCESSFUL; + } } ret = cli_nt_setup_netsec(cli, sec_channel_type, - AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, - trust_password); + AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password); return ret; } @@ -216,7 +235,8 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i /* Initialise SMB connection */ fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index)); -/* grab stored passwords */ + /* grab stored passwords */ + machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) { @@ -335,9 +355,13 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i /* try and use schannel if possible, but continue anyway if it failed. This allows existing setups to continue working, while solving the win2003 '100 user' limit for systems that - are joined properly */ - if (NT_STATUS_IS_OK(result) && (domain->primary)) { - NTSTATUS status = setup_schannel(new_conn->cli); + are joined properly. + + Only do this for our own domain or perhaps a trusted domain + if we are on a Samba DC */ + + if (NT_STATUS_IS_OK(result) && (domain->primary || IS_DC) ) { + NTSTATUS status = setup_schannel( new_conn->cli, domain->name ); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("schannel refused - continuing without schannel (%s)\n", nt_errstr(status))); diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c index 7b4529144e2..346a2711b6c 100644 --- a/source/nsswitch/winbindd_group.c +++ b/source/nsswitch/winbindd_group.c @@ -942,16 +942,14 @@ static void add_gid_to_array_unique(gid_t gid, gid_t **gids, int *num) *num += 1; } -static void add_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num) +static void add_local_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num) { gid_t gid; DOM_SID *aliases; int j, num_aliases; - DEBUG(10, ("Adding gids from SID: %s\n", sid_string_static(sid))); - - if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0))) - add_gid_to_array_unique(gid, gids, num); + DEBUG(10, ("Adding local gids from SID: %s\n", + sid_string_static(sid))); /* Don't expand aliases if not explicitly activated -- for now -- jerry */ @@ -965,15 +963,44 @@ static void add_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num) return; for (j=0; jother_sids[i].sid, - &gid_list, &num_gids); + add_gids_from_group_sid(&info3->other_sids[i].sid, + &gid_list, &num_gids); if (gid_list == NULL) goto done; @@ -1097,7 +1124,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) sid_copy( &group_sid, &domain->sid ); sid_append_rid( &group_sid, info3->gids[i].g_rid ); - add_gids_from_sid(&group_sid, &gid_list, &num_gids); + add_gids_from_group_sid(&group_sid, &gid_list, + &num_gids); if (gid_list == NULL) goto done; @@ -1116,8 +1144,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) goto done; for (i = 0; i < num_groups; i++) { - add_gids_from_sid(user_grpsids[i], - &gid_list, &num_gids); + add_gids_from_group_sid(user_grpsids[i], + &gid_list, &num_gids); if (gid_list == NULL) goto done; diff --git a/source/nsswitch/winbindd_passdb.c b/source/nsswitch/winbindd_passdb.c index 12f5e0bae2e..3adb81caa35 100644 --- a/source/nsswitch/winbindd_passdb.c +++ b/source/nsswitch/winbindd_passdb.c @@ -240,7 +240,11 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, if (!pdb_find_alias(name, sid)) return NT_STATUS_NONE_MAPPED; - *type = SID_NAME_ALIAS; + if (sid_check_is_in_builtin(sid)) + *type = SID_NAME_WKN_GRP; + else + *type = SID_NAME_ALIAS; + return NT_STATUS_OK; } @@ -263,7 +267,10 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, *domain_name = talloc_strdup(mem_ctx, domain->name); *name = talloc_strdup(mem_ctx, info.acct_name); - *type = SID_NAME_ALIAS; + if (sid_check_is_in_builtin(sid)) + *type = SID_NAME_WKN_GRP; + else + *type = SID_NAME_ALIAS; return NT_STATUS_OK; } diff --git a/source/nsswitch/winbindd_rpc.c b/source/nsswitch/winbindd_rpc.c index 76688449209..ba24749fbef 100644 --- a/source/nsswitch/winbindd_rpc.c +++ b/source/nsswitch/winbindd_rpc.c @@ -707,36 +707,6 @@ done: #include -static SIG_ATOMIC_T gotalarm; - -/*************************************************************** - Signal function to tell us we timed out. -****************************************************************/ - -static void gotalarm_sig(void) -{ - gotalarm = 1; -} - -static LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to) -{ - LDAP *ldp = NULL; - - /* Setup timeout */ - gotalarm = 0; - CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); - alarm(to); - /* End setup timeout. */ - - ldp = ldap_open(server, port); - - /* Teardown timeout. */ - CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN); - alarm(0); - - return ldp; -} - static int get_ldap_seq(const char *server, int port, uint32 *seq) { int ret = -1; @@ -749,11 +719,11 @@ static int get_ldap_seq(const char *server, int port, uint32 *seq) *seq = DOM_SEQUENCE_NONE; /* - * 10 second timeout on open. This is needed as the search timeout + * Parameterised (5) second timeout on open. This is needed as the search timeout * doesn't seem to apply to doing an open as well. JRA. */ - if ((ldp = ldap_open_with_timeout(server, port, 10)) == NULL) + if ((ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout())) == NULL) return -1; /* Timeout if no response within 20 seconds. */ diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c index 96b8ed8c938..faa6e8d8da4 100644 --- a/source/nsswitch/winbindd_util.c +++ b/source/nsswitch/winbindd_util.c @@ -175,7 +175,7 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const /* Link to domain list */ DLIST_ADD(_domain_list, domain); - DEBUG(1,("Added domain %s %s %s\n", + DEBUG(2,("Added domain %s %s %s\n", domain->name, domain->alt_name, &domain->sid?sid_string_static(&domain->sid):"")); diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 6376e4aa917..0710c36514b 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -231,8 +231,10 @@ typedef struct char *szLdapFilter; char *szLdapAdminDn; char *szAclCompat; + char *szCupsServer; int ldap_passwd_sync; int ldap_replication_sleep; + int ldap_timeout; /* This is initialised in init_globals */ BOOL ldap_delete_dn; BOOL bMsAddPrinterWizard; BOOL bDNSproxy; @@ -286,6 +288,8 @@ typedef struct BOOL bUnixExtensions; BOOL bDisableNetbios; BOOL bKernelChangeNotify; + BOOL bUseKerberosKeytab; + BOOL bDeferSharingViolations; int restrict_anonymous; int name_cache_timeout; int client_signing; @@ -363,7 +367,7 @@ typedef struct int iBlock_size; BOOL bPreexecClose; BOOL bRootpreexecClose; - BOOL bCaseSensitive; + int iCaseSensitive; BOOL bCasePreserve; BOOL bShortCasePreserve; BOOL bHideDotFiles; @@ -410,6 +414,7 @@ typedef struct BOOL bUseClientDriver; BOOL bDefaultDevmode; BOOL bNTAclSupport; + BOOL bForceUnknownAclUser; BOOL bUseSendfile; BOOL bProfileAcls; BOOL bMap_acl_inherit; @@ -486,7 +491,7 @@ static service sDefault = { 1024, /* iBlock_size */ False, /* bPreexecClose */ False, /* bRootpreexecClose */ - False, /* case sensitive */ + Auto, /* case sensitive */ True, /* case preserve */ True, /* short case preserve */ True, /* bHideDotFiles */ @@ -533,7 +538,8 @@ static service sDefault = { False, /* bUseClientDriver */ False, /* bDefaultDevmode */ True, /* bNTAclSupport */ - False, /* bUseSendfile */ + False, /* bForceUnknownAclUser */ + True, /* bUseSendfile */ False, /* bProfileAcls */ False, /* bMap_acl_inherit */ False, /* bAfs_Share */ @@ -846,6 +852,7 @@ static struct parm_struct parm_table[] = { {"force directory mode", P_OCTAL, P_LOCAL, &sDefault.iDir_force_mode, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE}, {"directory security mask", P_OCTAL, P_LOCAL, &sDefault.iDir_Security_mask, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE}, {"force directory security mode", P_OCTAL, P_LOCAL, &sDefault.iDir_Security_force_mode, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE}, + {"force unknown acl user", P_BOOL, P_LOCAL, &sDefault.bForceUnknownAclUser, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE}, {"inherit permissions", P_BOOL, P_LOCAL, &sDefault.bInheritPerms, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, {"inherit acls", P_BOOL, P_LOCAL, &sDefault.bInheritACLS, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, {"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, @@ -860,6 +867,7 @@ static struct parm_struct parm_table[] = { {"hosts deny", P_LIST, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_GLOBAL | FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT}, {"deny hosts", P_LIST, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_HIDE}, {"preload modules", P_LIST, P_GLOBAL, &Globals.szPreloadModules, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL}, + {"use kerberos keytab", P_BOOL, P_GLOBAL, &Globals.bUseKerberosKeytab, NULL, NULL, FLAG_ADVANCED}, {N_("Logging Options"), P_SEP, P_SEPARATOR}, @@ -889,6 +897,7 @@ static struct parm_struct parm_table[] = { {"disable netbios", P_BOOL, P_GLOBAL, &Globals.bDisableNetbios, NULL, NULL, FLAG_ADVANCED}, {"acl compatibility", P_STRING, P_GLOBAL, &Globals.szAclCompat, handle_acl_compatibility, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, + { "defer sharing violations", P_BOOL, P_GLOBAL, &Globals.bDeferSharingViolations, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL}, {"ea support", P_BOOL, P_LOCAL, &sDefault.bEASupport, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, {"nt acl support", P_BOOL, P_LOCAL, &sDefault.bNTAclSupport, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, {"nt pipe support", P_BOOL, P_GLOBAL, &Globals.bNTPipeSupport, NULL, NULL, FLAG_ADVANCED}, @@ -953,6 +962,7 @@ static struct parm_struct parm_table[] = { {"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, FLAG_HIDE}, {"printing", P_ENUM, P_LOCAL, &sDefault.iPrinting, handle_printing, enum_printing, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, {"cups options", P_STRING, P_LOCAL, &sDefault.szCupsOptions, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, + {"cups server", P_STRING, P_GLOBAL, &Globals.szCupsServer, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, {"print command", P_STRING, P_LOCAL, &sDefault.szPrintcommand, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, {"disable spoolss", P_BOOL, P_GLOBAL, &Globals.bDisableSpoolss, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, {"lpq command", P_STRING, P_LOCAL, &sDefault.szLpqcommand, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, @@ -978,8 +988,8 @@ static struct parm_struct parm_table[] = { {"mangle prefix", P_INTEGER, P_GLOBAL, &Globals.mangle_prefix, NULL, NULL, FLAG_ADVANCED}, {"default case", P_ENUM, P_LOCAL, &sDefault.iDefaultCase, NULL, enum_case, FLAG_ADVANCED | FLAG_SHARE}, - {"case sensitive", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, - {"casesignames", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL, FLAG_HIDE}, + {"case sensitive", P_ENUM, P_LOCAL, &sDefault.iCaseSensitive, NULL, enum_bool_auto, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, + {"casesignames", P_ENUM, P_LOCAL, &sDefault.iCaseSensitive, NULL, enum_bool_auto, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL | FLAG_HIDE}, {"preserve case", P_BOOL, P_LOCAL, &sDefault.bCasePreserve, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, {"short preserve case", P_BOOL, P_LOCAL, &sDefault.bShortCasePreserve, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, {"mangling char", P_CHAR, P_LOCAL, &sDefault.magic_char, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, @@ -1070,17 +1080,18 @@ static struct parm_struct parm_table[] = { {"ldap server", P_STRING, P_GLOBAL, &Globals.szLdapServer, NULL, NULL, FLAG_ADVANCED}, {"ldap port", P_INTEGER, P_GLOBAL, &Globals.ldap_port, NULL, NULL, FLAG_ADVANCED}, #endif - {"ldap suffix", P_STRING, P_GLOBAL, &Globals.szLdapSuffix, NULL, NULL, FLAG_ADVANCED}, - {"ldap machine suffix", P_STRING, P_GLOBAL, &Globals.szLdapMachineSuffix, NULL, NULL, FLAG_ADVANCED}, - {"ldap user suffix", P_STRING, P_GLOBAL, &Globals.szLdapUserSuffix, NULL, NULL, FLAG_ADVANCED}, + {"ldap admin dn", P_STRING, P_GLOBAL, &Globals.szLdapAdminDn, NULL, NULL, FLAG_ADVANCED}, + {"ldap delete dn", P_BOOL, P_GLOBAL, &Globals.ldap_delete_dn, NULL, NULL, FLAG_ADVANCED}, + {"ldap filter", P_STRING, P_GLOBAL, &Globals.szLdapFilter, NULL, NULL, FLAG_ADVANCED}, {"ldap group suffix", P_STRING, P_GLOBAL, &Globals.szLdapGroupSuffix, NULL, NULL, FLAG_ADVANCED}, {"ldap idmap suffix", P_STRING, P_GLOBAL, &Globals.szLdapIdmapSuffix, NULL, NULL, FLAG_ADVANCED}, - {"ldap filter", P_STRING, P_GLOBAL, &Globals.szLdapFilter, NULL, NULL, FLAG_ADVANCED}, - {"ldap admin dn", P_STRING, P_GLOBAL, &Globals.szLdapAdminDn, NULL, NULL, FLAG_ADVANCED}, - {"ldap ssl", P_ENUM, P_GLOBAL, &Globals.ldap_ssl, NULL, enum_ldap_ssl, FLAG_ADVANCED}, + {"ldap machine suffix", P_STRING, P_GLOBAL, &Globals.szLdapMachineSuffix, NULL, NULL, FLAG_ADVANCED}, {"ldap passwd sync", P_ENUM, P_GLOBAL, &Globals.ldap_passwd_sync, NULL, enum_ldap_passwd_sync, FLAG_ADVANCED}, - {"ldap delete dn", P_BOOL, P_GLOBAL, &Globals.ldap_delete_dn, NULL, NULL, FLAG_ADVANCED}, {"ldap replication sleep", P_INTEGER, P_GLOBAL, &Globals.ldap_replication_sleep, NULL, NULL, FLAG_ADVANCED}, + {"ldap suffix", P_STRING, P_GLOBAL, &Globals.szLdapSuffix, NULL, NULL, FLAG_ADVANCED}, + {"ldap ssl", P_ENUM, P_GLOBAL, &Globals.ldap_ssl, NULL, enum_ldap_ssl, FLAG_ADVANCED}, + {"ldap timeout", P_INTEGER, P_GLOBAL, &Globals.ldap_timeout, NULL, NULL, FLAG_ADVANCED}, + {"ldap user suffix", P_STRING, P_GLOBAL, &Globals.szLdapUserSuffix, NULL, NULL, FLAG_ADVANCED}, {N_("Miscellaneous Options"), P_SEP, P_SEPARATOR}, {"add share command", P_STRING, P_GLOBAL, &Globals.szAddShareCommand, NULL, NULL, FLAG_ADVANCED}, @@ -1289,6 +1300,13 @@ static void init_globals(void) if (!done_init) { int i; + + /* The logfile can be set before this is invoked. Free it if so. */ + if (Globals.szLogFile != NULL) { + string_free(&Globals.szLogFile); + Globals.szLogFile = NULL; + } + memset((void *)&Globals, '\0', sizeof(Globals)); for (i = 0; parm_table[i].label; i++) @@ -1471,6 +1489,7 @@ static void init_globals(void) Globals.ldap_passwd_sync = LDAP_PASSWD_SYNC_OFF; Globals.ldap_delete_dn = False; Globals.ldap_replication_sleep = 1000; /* wait 1 sec for replication */ + Globals.ldap_timeout = LDAP_CONNECT_DEFAULT_TIMEOUT; /* these parameters are set to defaults that are more appropriate for the increasing samba install base: @@ -1506,6 +1525,7 @@ static void init_globals(void) string_set(&Globals.szTemplatePrimaryGroup, "nobody"); string_set(&Globals.szWinbindSeparator, "\\"); string_set(&Globals.szAclCompat, ""); + string_set(&Globals.szCupsServer, ""); Globals.winbind_cache_time = 300; /* 5 minutes */ Globals.bWinbindEnableLocalAccounts = True; @@ -1525,6 +1545,7 @@ static void init_globals(void) Globals.client_signing = Auto; Globals.server_signing = False; + Globals.bDeferSharingViolations = True; string_set(&Globals.smb_ports, SMB_PORTS); } @@ -1703,6 +1724,7 @@ FN_GLOBAL_INTEGER(lp_ldap_ssl, &Globals.ldap_ssl) FN_GLOBAL_INTEGER(lp_ldap_passwd_sync, &Globals.ldap_passwd_sync) FN_GLOBAL_BOOL(lp_ldap_delete_dn, &Globals.ldap_delete_dn) FN_GLOBAL_INTEGER(lp_ldap_replication_sleep, &Globals.ldap_replication_sleep) +FN_GLOBAL_INTEGER(lp_ldap_timeout, &Globals.ldap_timeout) FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand) FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand) FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand) @@ -1758,6 +1780,8 @@ FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego) FN_GLOBAL_BOOL(lp_client_use_spnego, &Globals.bClientUseSpnego) FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups) FN_GLOBAL_BOOL(lp_kernel_change_notify, &Globals.bKernelChangeNotify) +FN_GLOBAL_BOOL(lp_use_kerberos_keytab, &Globals.bUseKerberosKeytab) +FN_GLOBAL_BOOL(lp_defer_sharing_violations, &Globals.bDeferSharingViolations) FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level) FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl) FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl) @@ -1802,6 +1826,7 @@ FN_LOCAL_LIST(lp_invalid_users, szInvalidUsers) FN_LOCAL_LIST(lp_valid_users, szValidUsers) FN_LOCAL_LIST(lp_admin_users, szAdminUsers) FN_LOCAL_STRING(lp_cups_options, szCupsOptions) +FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer) FN_LOCAL_STRING(lp_printcommand, szPrintcommand) FN_LOCAL_STRING(lp_lpqcommand, szLpqcommand) FN_LOCAL_STRING(lp_lprmcommand, szLprmcommand) @@ -1832,7 +1857,7 @@ FN_LOCAL_BOOL(lp_msdfs_root, bMSDfsRoot) FN_LOCAL_BOOL(lp_autoloaded, autoloaded) FN_LOCAL_BOOL(lp_preexec_close, bPreexecClose) FN_LOCAL_BOOL(lp_rootpreexec_close, bRootpreexecClose) -FN_LOCAL_BOOL(lp_casesensitive, bCaseSensitive) +FN_LOCAL_INTEGER(lp_casesensitive, iCaseSensitive) FN_LOCAL_BOOL(lp_preservecase, bCasePreserve) FN_LOCAL_BOOL(lp_shortpreservecase, bShortCasePreserve) FN_LOCAL_BOOL(lp_hide_dot_files, bHideDotFiles) @@ -1875,6 +1900,7 @@ FN_LOCAL_BOOL(lp_inherit_acls, bInheritACLS) FN_LOCAL_BOOL(lp_use_client_driver, bUseClientDriver) FN_LOCAL_BOOL(lp_default_devmode, bDefaultDevmode) FN_LOCAL_BOOL(lp_nt_acl_support, bNTAclSupport) +FN_LOCAL_BOOL(lp_force_unknown_acl_user, bForceUnknownAclUser) FN_LOCAL_BOOL(lp_ea_support, bEASupport) FN_LOCAL_BOOL(_lp_use_sendfile, bUseSendfile) FN_LOCAL_BOOL(lp_profile_acls, bProfileAcls) @@ -2315,6 +2341,8 @@ BOOL lp_add_home(const char *pszHomename, int iDefaultService, ServicePtrs[i]->bBrowseable = sDefault.bBrowseable; + ServicePtrs[i]->autoloaded = True; + DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n", pszHomename, user, newHomedir)); @@ -2993,10 +3021,8 @@ static void lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue { int i; - for (i = 0; parm->enum_list[i].name; i++) - { - if ( strequal(pszParmValue, parm->enum_list[i].name)) - { + for (i = 0; parm->enum_list[i].name; i++) { + if ( strequal(pszParmValue, parm->enum_list[i].name)) { *ptr = parm->enum_list[i].value; break; } @@ -3269,9 +3295,9 @@ static void print_parameter(struct parm_struct *p, void *ptr, FILE * f) char **list = *(char ***)ptr; for (; *list; list++) { - /* surround strings with whitespace in single quotes */ + /* surround strings with whitespace in double quotes */ if ( strchr_m( *list, ' ' ) ) - fprintf(f, "\'%s\'%s", *list, ((*(list+1))?", ":"")); + fprintf(f, "\"%s\"%s", *list, ((*(list+1))?", ":"")); else fprintf(f, "%s%s", *list, ((*(list+1))?", ":"")); } @@ -3697,6 +3723,10 @@ void lp_killunused(BOOL (*snumused) (int)) if (!VALID(i)) continue; + /* don't kill autoloaded services */ + if ( ServicePtrs[i]->autoloaded ) + continue; + if (!snumused || !snumused(i)) { ServicePtrs[i]->valid = False; free_service(ServicePtrs[i]); @@ -3866,11 +3896,12 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults, /* get the username for substituion -- preference to the current_user_info */ - if ( strlen( current_user_info.smb_name ) != 0 ) + if ( strlen( current_user_info.smb_name ) != 0 ) { username = current_user_info.smb_name; - else + } else { username = sub_get_smb_name(); - + } + standard_sub_basic( username, n2,sizeof(n2) ); add_to_file_list(pszFname, n2); @@ -3885,8 +3916,7 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults, init_globals(); debug_init(); - if (save_defaults) - { + if (save_defaults) { init_locals(); lp_save_defaults(); } @@ -4258,7 +4288,10 @@ const char *get_called_name(void) extern fstring local_machine; static fstring called_name; - if (!*local_machine) { + if ( (!*local_machine) || + (client_socket_port() == 445) ) { + /* Everybody coming in on 445 should be able to live with the + * IP address */ fstrcpy(called_name, client_socket_addr()); DEBUG(8,("get_called_name: assuming that client used IP address [%s] as called name.\n", called_name)); @@ -4289,3 +4322,14 @@ BOOL lp_use_sendfile(int snum) { return (_lp_use_sendfile(snum) && !srv_is_signing_active()); } + +/******************************************************************* + Turn off storing DOS attributes if this share doesn't support it. +********************************************************************/ + +void set_store_dos_attributes(int snum, BOOL val) +{ + if (!LP_SNUM_OK(snum)) + return; + ServicePtrs[(snum)]->bStoreDosAttributes = val; +} diff --git a/source/passdb/login_cache.c b/source/passdb/login_cache.c index fc05122ccaf..0d782912b17 100644 --- a/source/passdb/login_cache.c +++ b/source/passdb/login_cache.c @@ -95,10 +95,13 @@ LOGIN_CACHE * login_cache_read(SAM_ACCOUNT *sampass) &entry->bad_password_count, &entry->bad_password_time) == -1) { DEBUG(7, ("No cache entry found\n")); + SAFE_FREE(entry); SAFE_FREE(databuf.dptr); return NULL; } + SAFE_FREE(databuf.dptr); + DEBUG(5, ("Found login cache entry: timestamp %12u, flags 0x%x, count %d, time %12u\n", (unsigned int)entry->entry_timestamp, entry->acct_ctrl, entry->bad_password_count, (unsigned int)entry->bad_password_time)); diff --git a/source/passdb/lookup_sid.c b/source/passdb/lookup_sid.c index 842db8de5dc..d536383ef3e 100644 --- a/source/passdb/lookup_sid.c +++ b/source/passdb/lookup_sid.c @@ -445,14 +445,11 @@ NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid) * Group mapping can deal with foreign SIDs */ + if ( local_sid_to_gid(pgid, psid, &name_type) ) + goto success; + if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) { - DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n", - sid_to_string(sid_str, psid) )); - - if ( local_sid_to_gid(pgid, psid, &name_type) ) - goto success; - - DEBUG(10,("sid_to_gid: no one knows this SID\n")); + DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid))); return NT_STATUS_UNSUCCESSFUL; } diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c index 75f8171a25d..c3a423c2636 100644 --- a/source/passdb/passdb.c +++ b/source/passdb/passdb.c @@ -1287,6 +1287,7 @@ BOOL local_sid_to_gid(gid_t *pgid, const DOM_SID *psid, enum SID_NAME_USE *name_ } *pgid = group.gid; + *name_type = group.sid_name_use; DEBUG(10,("local_sid_to_gid: SID %s -> gid (%u)\n", sid_string_static(psid), (unsigned int)*pgid)); diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c index 15635a034cc..d2ee9a2d9dc 100644 --- a/source/passdb/pdb_ldap.c +++ b/source/passdb/pdb_ldap.c @@ -1043,9 +1043,13 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, DEBUG(7, ("bad password count is reset, deleting login cache entry for %s\n", pdb_get_nt_username(sampass))); login_cache_delentry(sampass); } else { - LOGIN_CACHE cache_entry ={time(NULL), - pdb_get_acct_ctrl(sampass), - badcount, badtime}; + LOGIN_CACHE cache_entry; + + cache_entry.entry_timestamp = time(NULL); + cache_entry.acct_ctrl = pdb_get_acct_ctrl(sampass); + cache_entry.bad_password_count = badcount; + cache_entry.bad_password_time = badtime; + DEBUG(7, ("Updating bad password count and time in login cache\n")); login_cache_write(sampass, cache_entry); } @@ -1130,6 +1134,19 @@ static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT return NT_STATUS_OK; } +static void append_attr(char ***attr_list, const char *new_attr) +{ + int i; + + for (i=0; (*attr_list)[i] != NULL; i++) + ; + + (*attr_list) = Realloc((*attr_list), sizeof(**attr_list) * (i+2)); + SMB_ASSERT((*attr_list) != NULL); + (*attr_list)[i] = strdup(new_attr); + (*attr_list)[i+1] = NULL; +} + /********************************************************************** Get SAM_ACCOUNT entry from LDAP by username. *********************************************************************/ @@ -1145,6 +1162,7 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT int rc; attr_list = get_userattr_list( ldap_state->schema_ver ); + append_attr(&attr_list, MODIFY_TIMESTAMP_STRING); rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list); free_attr_list( attr_list ); @@ -1190,6 +1208,7 @@ static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state, switch ( ldap_state->schema_ver ) { case SCHEMAVER_SAMBASAMACCOUNT: attr_list = get_userattr_list(ldap_state->schema_ver); + append_attr(&attr_list, MODIFY_TIMESTAMP_STRING); rc = ldapsam_search_suffix_by_sid(ldap_state, sid, result, attr_list); free_attr_list( attr_list ); diff --git a/source/printing/notify.c b/source/printing/notify.c index 26ef191f877..8d5be136071 100644 --- a/source/printing/notify.c +++ b/source/printing/notify.c @@ -278,7 +278,7 @@ in notify_queue\n", msg->type, msg->field, msg->printer)); return; } copy_notify2_msg(pnqueue->msg, msg); - gettimeofday(&pnqueue->tv, NULL); + GetTimeOfDay(&pnqueue->tv); pnqueue->buf = NULL; pnqueue->buflen = 0; diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index 909aed6c866..225ff20ec3e 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -1003,9 +1003,9 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); fsp = open_file_shared(conn, filepath, &stat_buf, - SET_OPEN_MODE(DOS_OPEN_RDONLY), + SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action); + FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); if (!fsp) { /* Old file not found, so by definition new file is in fact newer */ DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n", @@ -1032,9 +1032,9 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); fsp = open_file_shared(conn, filepath, &stat_buf, - SET_OPEN_MODE(DOS_OPEN_RDONLY), + SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action); + FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); if (!fsp) { /* New file not found, this shouldn't occur if the caller did its job */ DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n", @@ -1148,9 +1148,9 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ driver_unix_convert(driverpath,conn,NULL,&bad_path,&st); fsp = open_file_shared(conn, driverpath, &st, - SET_OPEN_MODE(DOS_OPEN_RDONLY), + SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action); + FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); if (!fsp) { DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n", driverpath, errno)); diff --git a/source/printing/print_cups.c b/source/printing/print_cups.c index 9a48296543d..3097811fac2 100644 --- a/source/printing/print_cups.c +++ b/source/printing/print_cups.c @@ -65,6 +65,17 @@ cups_passwd_cb(const char *prompt) /* I - Prompt */ return (NULL); } +static const char *cups_server(void) +{ + if ((lp_cups_server() != NULL) && (strlen(lp_cups_server()) > 0)) { + DEBUG(10, ("cups server explicitly set to %s\n", + lp_cups_server())); + return lp_cups_server(); + } + + DEBUG(10, ("cups server left to default %s\n", cupsServer())); + return cupsServer(); +} /* * 'cups_printer_fn()' - Call a function for every printer known to the @@ -102,10 +113,10 @@ void cups_printer_fn(void (*fn)(char *, char *)) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(0,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return; } @@ -331,10 +342,10 @@ int cups_printername_ok(const char *name) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(3,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return (0); } @@ -425,10 +436,10 @@ cups_job_delete(int snum, struct printjob *pjob) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(0,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return (1); } @@ -515,10 +526,10 @@ cups_job_pause(int snum, struct printjob *pjob) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(0,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return (1); } @@ -605,10 +616,10 @@ cups_job_resume(int snum, struct printjob *pjob) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(0,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return (1); } @@ -698,10 +709,10 @@ cups_job_submit(int snum, struct printjob *pjob) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(0,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return (1); } @@ -848,10 +859,10 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(0,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return (0); } @@ -1153,10 +1164,10 @@ cups_queue_pause(int snum) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(0,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return (1); } @@ -1245,10 +1256,10 @@ cups_queue_resume(int snum) * Try to connect to the server... */ - if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + if ((http = httpConnect(cups_server(), ippPort())) == NULL) { DEBUG(0,("Unable to connect to CUPS server %s - %s\n", - cupsServer(), strerror(errno))); + cups_server(), strerror(errno))); return (1); } diff --git a/source/printing/printing.c b/source/printing/printing.c index 2274e2d5f45..8beea9d0cec 100644 --- a/source/printing/printing.c +++ b/source/printing/printing.c @@ -23,6 +23,9 @@ #include "includes.h" #include "printing.h" +extern SIG_ATOMIC_T got_sig_term; +extern SIG_ATOMIC_T reload_after_sighup; + /* Current printer interface */ static BOOL remove_from_jobs_changed(int snum, uint32 jobid); @@ -597,6 +600,7 @@ void pjob_delete(int snum, uint32 jobid) tdb_delete(pdb->tdb, print_key(jobid)); release_print_db(pdb); rap_jobid_delete(snum, jobid); + remove_from_jobs_changed( snum, jobid ); } /**************************************************************************** @@ -1195,6 +1199,22 @@ void start_background_queue(void) DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n")); while (1) { pause(); + + /* check for some essential signals first */ + + if (got_sig_term) { + exit_server("Caught TERM signal"); + } + + if (reload_after_sighup) { + change_to_root_user(); + DEBUG(1,("Reloading services after SIGHUP\n")); + reload_services(False); + reload_after_sighup = 0; + } + + /* now check for messages */ + DEBUG(10,("start_background_queue: background LPQ thread got a message\n")); message_dispatch(); } @@ -1211,9 +1231,13 @@ static void print_queue_update(int snum) * Otherwise just do the update ourselves */ - if ( background_lpq_updater_pid != -1 ) - message_send_pid(background_lpq_updater_pid, MSG_PRINTER_UPDATE, &snum, sizeof(snum), False); - else + if ( background_lpq_updater_pid != -1 ) { + become_root(); + message_send_pid(background_lpq_updater_pid, + MSG_PRINTER_UPDATE, &snum, sizeof(snum), + False); + unbecome_root(); + } else print_queue_update_internal( snum ); } diff --git a/source/printing/printing_db.c b/source/printing/printing_db.c index d402aa366f4..9efb3e8eadf 100644 --- a/source/printing/printing_db.c +++ b/source/printing/printing_db.c @@ -96,8 +96,8 @@ struct tdb_print_db *get_print_db_byname(const char *printername) done_become_root = True; } - p->tdb = tdb_open_ex(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT, - 0600, smbd_tdb_log); + p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT, + 0600); if (done_become_root) unbecome_root(); diff --git a/source/rpc_client/cli_netlogon.c b/source/rpc_client/cli_netlogon.c index f6d88a19501..02d2611d88c 100644 --- a/source/rpc_client/cli_netlogon.c +++ b/source/rpc_client/cli_netlogon.c @@ -91,18 +91,25 @@ NTSTATUS cli_net_auth2(struct cli_state *cli, NET_Q_AUTH_2 q; NET_R_AUTH_2 r; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + fstring machine_acct; prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL); prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL); + if ( sec_chan == SEC_CHAN_DOMAIN ) + fstr_sprintf( machine_acct, "%s$", lp_workgroup() ); + else + fstrcpy( machine_acct, cli->mach_acct ); + /* create and send a MSRPC command with api NET_AUTH2 */ DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n", - cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname(), + cli->srv_name_slash, machine_acct, sec_chan, global_myname(), credstr(cli->clnt_cred.challenge.data), *neg_flags)); /* store the parameters */ - init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct, + + init_q_auth_2(&q, cli->srv_name_slash, machine_acct, sec_chan, global_myname(), &cli->clnt_cred.challenge, *neg_flags); diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c index b24dbb7d25d..0720f872419 100644 --- a/source/rpc_client/cli_pipe.c +++ b/source/rpc_client/cli_pipe.c @@ -1233,10 +1233,12 @@ static BOOL valid_pipe_name(const int pipe_idx, RPC_IFACE *abstract, RPC_IFACE * static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const int pipe_idx, RPC_IFACE *transfer) { -# if 0 /* JERRY -- apparently ASU forgets to fill in the server pipe name sometimes */ - if ( hdr_ba->addr.len <= 0) - return False; + if ( hdr_ba->addr.len == 0) { + DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)")); + } + +# if 0 /* JERRY -- apparently ASU forgets to fill in the server pipe name sometimes */ if ( !strequal(hdr_ba->addr.str, pipe_names[pipe_idx].client_pipe) && !strequal(hdr_ba->addr.str, pipe_names[pipe_idx].server_pipe) ) { @@ -1621,9 +1623,6 @@ NTSTATUS cli_nt_setup_netsec(struct cli_state *cli, int sec_chan, int auth_flags return NT_STATUS_UNSUCCESSFUL; } - if (lp_client_schannel() != False) - neg_flags |= NETLOGON_NEG_SCHANNEL; - neg_flags |= NETLOGON_NEG_SCHANNEL; result = cli_nt_setup_creds(cli, sec_chan, trust_password, diff --git a/source/rpc_parse/parse_net.c b/source/rpc_parse/parse_net.c index 36d55c7bf67..b42b9b2a8b4 100644 --- a/source/rpc_parse/parse_net.c +++ b/source/rpc_parse/parse_net.c @@ -182,6 +182,50 @@ static BOOL net_io_netinfo_2(const char *desc, NETLOGON_INFO_2 *info, prs_struct return True; } +static BOOL net_io_ctrl_data_info_5(const char *desc, CTRL_DATA_INFO_5 *info, prs_struct *ps, int depth) +{ + if (info == NULL) + return False; + + prs_debug(ps, depth, desc, "net_io_ctrl_data_info_5"); + depth++; + + if ( !prs_uint32( "function_code", ps, depth, &info->function_code ) ) + return False; + + if(!prs_uint32("ptr_domain", ps, depth, &info->ptr_domain)) + return False; + + if ( info->ptr_domain ) { + if(!smb_io_unistr2("domain", &info->domain, info->ptr_domain, ps, depth)) + return False; + } + + return True; +} + +static BOOL net_io_ctrl_data_info_6(const char *desc, CTRL_DATA_INFO_6 *info, prs_struct *ps, int depth) +{ + if (info == NULL) + return False; + + prs_debug(ps, depth, desc, "net_io_ctrl_data_info_6"); + depth++; + + if ( !prs_uint32( "function_code", ps, depth, &info->function_code ) ) + return False; + + if(!prs_uint32("ptr_domain", ps, depth, &info->ptr_domain)) + return False; + + if ( info->ptr_domain ) { + if(!smb_io_unistr2("domain", &info->domain, info->ptr_domain, ps, depth)) + return False; + } + + return True; +} + /******************************************************************* Reads or writes an NET_Q_LOGON_CTRL2 structure. ********************************************************************/ @@ -210,9 +254,23 @@ BOOL net_io_q_logon_ctrl2(const char *desc, NET_Q_LOGON_CTRL2 *q_l, prs_struct * return False; if(!prs_uint32("query_level ", ps, depth, &q_l->query_level)) return False; - if(!prs_uint32("switch_value ", ps, depth, &q_l->switch_value)) - return False; + switch ( q_l->function_code ) { + case NETLOGON_CONTROL_REDISCOVER: + if ( !net_io_ctrl_data_info_5( "ctrl_data_info5", &q_l->info.info5, ps, depth) ) + return False; + break; + + case NETLOGON_CONTROL_TC_QUERY: + if ( !net_io_ctrl_data_info_6( "ctrl_data_info6", &q_l->info.info6, ps, depth) ) + return False; + break; + default: + DEBUG(0,("net_io_q_logon_ctrl2: unknown function_code [%d]\n", + q_l->function_code)); + return False; + } + return True; } @@ -227,7 +285,6 @@ void init_net_q_logon_ctrl2(NET_Q_LOGON_CTRL2 *q_l, const char *srv_name, q_l->function_code = 0x01; q_l->query_level = query_level; - q_l->switch_value = 0x01; init_unistr2(&q_l->uni_server_name, srv_name, UNI_STR_TERMINATE); } @@ -241,9 +298,7 @@ void init_net_r_logon_ctrl2(NET_R_LOGON_CTRL2 *r_l, uint32 query_level, uint32 logon_attempts, uint32 tc_status, const char *trusted_domain_name) { - DEBUG(5,("init_r_logon_ctrl2\n")); - - r_l->switch_value = query_level; /* should only be 0x1 */ + r_l->switch_value = query_level; switch (query_level) { case 1: diff --git a/source/rpc_parse/parse_prs.c b/source/rpc_parse/parse_prs.c index 0e5a25fe8c2..92c5b13632a 100644 --- a/source/rpc_parse/parse_prs.c +++ b/source/rpc_parse/parse_prs.c @@ -1101,10 +1101,13 @@ BOOL prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str) /* the test of the value of *ptr helps to catch the circumstance where we have an emtpty (non-existent) string in the buffer */ - for ( ptr = (uint16 *)q; *ptr && (alloc_len <= max_len); alloc_len++) + for ( ptr = (uint16 *)q; *ptr++ && (alloc_len <= max_len); alloc_len++) /* do nothing */ ; + if (alloc_len < max_len) + alloc_len += 1; + /* should we allocate anything at all? */ str->buffer = (uint16 *)prs_alloc_mem(ps,alloc_len * sizeof(uint16)); if ((str->buffer == NULL) && (alloc_len > 0)) diff --git a/source/rpc_parse/parse_samr.c b/source/rpc_parse/parse_samr.c index 85eedc7baab..bb4c94404b0 100644 --- a/source/rpc_parse/parse_samr.c +++ b/source/rpc_parse/parse_samr.c @@ -2204,12 +2204,17 @@ reads or writes a structure. BOOL samr_io_group_info1(const char *desc, GROUP_INFO1 * gr1, prs_struct *ps, int depth) { + uint16 dummy = 1; + if (gr1 == NULL) return False; prs_debug(ps, depth, desc, "samr_io_group_info1"); depth++; + if(!prs_uint16("level", ps, depth, &dummy)) + return False; + if(!prs_align(ps)) return False; @@ -2236,6 +2241,43 @@ BOOL samr_io_group_info1(const char *desc, GROUP_INFO1 * gr1, } /******************************************************************* +inits a GROUP_INFO2 structure. +********************************************************************/ + +void init_samr_group_info2(GROUP_INFO2 * gr2, const char *acct_name) +{ + DEBUG(5, ("init_samr_group_info2\n")); + + gr2->level = 2; + init_unistr2(&gr2->uni_acct_name, acct_name, UNI_FLAGS_NONE); + init_uni_hdr(&gr2->hdr_acct_name, &gr2->uni_acct_name); +} + +/******************************************************************* +reads or writes a structure. +********************************************************************/ + +BOOL samr_io_group_info2(const char *desc, GROUP_INFO2 *gr2, prs_struct *ps, int depth) +{ + if (gr2 == NULL) + return False; + + prs_debug(ps, depth, desc, "samr_io_group_info2"); + depth++; + + if(!prs_uint16("hdr_level", ps, depth, &gr2->level)) + return False; + + if(!smb_io_unihdr("hdr_acct_name", &gr2->hdr_acct_name, ps, depth)) + return False; + if(!smb_io_unistr2("uni_acct_name", &gr2->uni_acct_name, + gr2->hdr_acct_name.buffer, ps, depth)) + return False; + + return True; +} + +/******************************************************************* inits a GROUP_INFO3 structure. ********************************************************************/ @@ -2328,6 +2370,10 @@ static BOOL samr_group_info_ctr(const char *desc, GROUP_INFO_CTR **ctr, if(!samr_io_group_info1("group_info1", &(*ctr)->group.info1, ps, depth)) return False; break; + case 2: + if(!samr_io_group_info2("group_info2", &(*ctr)->group.info2, ps, depth)) + return False; + break; case 3: if(!samr_io_group_info3("group_info3", &(*ctr)->group.info3, ps, depth)) return False; @@ -6924,8 +6970,7 @@ BOOL samr_io_r_get_dom_pwinfo(const char *desc, SAMR_R_GET_DOM_PWINFO * r_u, return False; /* - * We need 16 bytes here according to tests. Don't know - * what they are, but the length is important for the singing + * see the Samba4 IDL for what these actually are. */ if(!prs_uint16("unk_0", ps, depth, &r_u->unk_0)) diff --git a/source/rpc_server/srv_lsa_nt.c b/source/rpc_server/srv_lsa_nt.c index b4e29e67485..6c3157d5c95 100644 --- a/source/rpc_server/srv_lsa_nt.c +++ b/source/rpc_server/srv_lsa_nt.c @@ -101,7 +101,7 @@ static int init_dom_ref(DOM_R_REF *ref, char *dom_name, DOM_SID *dom_sid) if (dom_name != NULL) { for (num = 0; num < ref->num_ref_doms_1; num++) { fstring domname; - rpcstr_pull(domname, &ref->ref_dom[num].uni_dom_name, sizeof(domname), -1, 0); + rpcstr_pull(domname, ref->ref_dom[num].uni_dom_name.buffer, sizeof(domname), -1, 0); if (strequal(domname, dom_name)) return num; } @@ -719,12 +719,12 @@ done: /* set up the LSA Lookup RIDs response */ init_lsa_rid2s(ref, rids, num_entries, names, &mapped_count, p->endian); - if (mapped_count == 0) - r_u->status = NT_STATUS_NONE_MAPPED; - else if (mapped_count != num_entries) - r_u->status = STATUS_SOME_UNMAPPED; - else - r_u->status = NT_STATUS_OK; + if (NT_STATUS_IS_OK(r_u->status)) { + if (mapped_count == 0) + r_u->status = NT_STATUS_NONE_MAPPED; + else if (mapped_count != num_entries) + r_u->status = STATUS_SOME_UNMAPPED; + } init_reply_lookup_names(r_u, ref, num_entries, rids, mapped_count); return r_u->status; diff --git a/source/rpc_server/srv_netlog.c b/source/rpc_server/srv_netlog.c index f06a2002e3c..705b629732a 100644 --- a/source/rpc_server/srv_netlog.c +++ b/source/rpc_server/srv_netlog.c @@ -227,8 +227,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p) ZERO_STRUCT(q_u); ZERO_STRUCT(r_u); - DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__)); - /* grab the lsa trusted domain list query... */ if(!net_io_q_trust_dom("", &q_u, data, 0)) { DEBUG(0,("api_net_trust_dom_list: Failed to unmarshall NET_Q_TRUST_DOM_LIST.\n")); @@ -244,8 +242,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p) return False; } - DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__)); - return True; } @@ -263,7 +259,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p) ZERO_STRUCT(q_u); ZERO_STRUCT(r_u); - DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__)); /* grab the lsa netlogon ctrl2 query... */ if(!net_io_q_logon_ctrl2("", &q_u, data, 0)) { @@ -278,8 +273,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p) return False; } - DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__)); - return True; } @@ -297,8 +290,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p) ZERO_STRUCT(q_u); ZERO_STRUCT(r_u); - DEBUG(6,("api_net_logon_ctrl: %d\n", __LINE__)); - /* grab the lsa netlogon ctrl query... */ if(!net_io_q_logon_ctrl("", &q_u, data, 0)) { DEBUG(0,("api_net_logon_ctrl: Failed to unmarshall NET_Q_LOGON_CTRL.\n")); @@ -312,8 +303,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p) return False; } - DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__)); - return True; } diff --git a/source/rpc_server/srv_netlog_nt.c b/source/rpc_server/srv_netlog_nt.c index be8eda82c90..264b7a74a79 100644 --- a/source/rpc_server/srv_netlog_nt.c +++ b/source/rpc_server/srv_netlog_nt.c @@ -47,6 +47,7 @@ static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c, #define ERROR_NO_SUCH_DOMAIN 0x54b #define ERROR_NO_LOGON_SERVERS 0x51f +#define NO_ERROR 0x0 /************************************************************************* net_reply_logon_ctrl: @@ -104,25 +105,67 @@ NTSTATUS _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_C uint32 flags = 0x0; uint32 pdc_connection_status = 0x0; uint32 logon_attempts = 0x0; - uint32 tc_status = ERROR_NO_LOGON_SERVERS; - const char *trusted_domain = "test_domain"; + uint32 tc_status; + fstring servername, domain, dc_name, dc_name2; + struct in_addr dc_ip; - DEBUG(0, ("*** net long ctrl2 %d, %d, %d\n", - q_u->function_code, q_u->query_level, q_u->switch_value)); + /* this should be \\global_myname() */ + unistr2_to_ascii(servername, &q_u->uni_server_name, sizeof(servername)); - DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__)); - - - /* set up the Logon Control2 response */ - init_net_r_logon_ctrl2(r_u, q_u->query_level, - flags, pdc_connection_status, logon_attempts, - tc_status, trusted_domain); + r_u->status = NT_STATUS_OK; + + tc_status = ERROR_NO_SUCH_DOMAIN; + fstrcpy( dc_name, "" ); + + switch ( q_u->function_code ) { + case NETLOGON_CONTROL_TC_QUERY: + unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain)); + + if ( !is_trusted_domain( domain ) ) + break; + + if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) { + tc_status = ERROR_NO_LOGON_SERVERS; + break; + } + + fstr_sprintf( dc_name, "\\\\%s", dc_name2 ); + + tc_status = NO_ERROR; + + break; + + case NETLOGON_CONTROL_REDISCOVER: + unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain)); + + if ( !is_trusted_domain( domain ) ) + break; + + if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) { + tc_status = ERROR_NO_LOGON_SERVERS; + break; + } + + fstr_sprintf( dc_name, "\\\\%s", dc_name2 ); + + tc_status = NO_ERROR; + + break; + + default: + /* no idea what this should be */ + DEBUG(0,("_net_logon_ctrl2: unimplemented function level [%d]\n", + q_u->function_code)); + } + + /* prepare the response */ + + init_net_r_logon_ctrl2( r_u, q_u->query_level, flags, + pdc_connection_status, logon_attempts, tc_status, dc_name ); if (lp_server_role() == ROLE_DOMAIN_BDC) send_sync_message(); - DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__)); - return r_u->status; } diff --git a/source/rpc_server/srv_pipe.c b/source/rpc_server/srv_pipe.c index 13d894d2d88..36929150e54 100644 --- a/source/rpc_server/srv_pipe.c +++ b/source/rpc_server/srv_pipe.c @@ -1397,7 +1397,7 @@ BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in) SENDER_IS_INITIATOR, &netsec_chk, prs_data_p(rpc_in)+old_offset, data_len)) { - DEBUG(0,("failed to decode PDU\n")); + DEBUG(3,("failed to decode PDU\n")); return False; } diff --git a/source/rpc_server/srv_pipe_hnd.c b/source/rpc_server/srv_pipe_hnd.c index ccf571a0e2c..7f7a3025a90 100644 --- a/source/rpc_server/srv_pipe_hnd.c +++ b/source/rpc_server/srv_pipe_hnd.c @@ -602,7 +602,7 @@ static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) } if (p->netsec_auth_validated && !api_pipe_netsec_process(p, rpc_in_p)) { - DEBUG(0,("process_request_pdu: failed to do schannel processing.\n")); + DEBUG(3,("process_request_pdu: failed to do schannel processing.\n")); set_incoming_fault(p); return False; } diff --git a/source/rpc_server/srv_samr_util.c b/source/rpc_server/srv_samr_util.c index 417a712036a..8cc44074abe 100644 --- a/source/rpc_server/srv_samr_util.c +++ b/source/rpc_server/srv_samr_util.c @@ -240,6 +240,12 @@ void copy_id21_to_sam_passwd(SAM_ACCOUNT *to, SAM_USER_INFO_21 *from) if (from->fields_present & ACCT_FLAGS) { DEBUG(10,("INFO_21 ACCT_CTRL: %08X -> %08X\n",pdb_get_acct_ctrl(to),from->acb_info)); if (from->acb_info != pdb_get_acct_ctrl(to)) { + if (!(from->acb_info & ACB_AUTOLOCK) && (pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) { + /* We're unlocking a previously locked user. Reset bad password counts. + Patch from Jianliang Lu. */ + pdb_set_bad_password_count(to, 0, PDB_CHANGED); + pdb_set_bad_password_time(to, 0, PDB_CHANGED); + } pdb_set_acct_ctrl(to, from->acb_info, PDB_CHANGED); } } diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c index 65d5517da45..06ba5435976 100644 --- a/source/rpc_server/srv_spoolss_nt.c +++ b/source/rpc_server/srv_spoolss_nt.c @@ -5,7 +5,7 @@ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000, * Copyright (C) Jean François Micouleau 1998-2000, * Copyright (C) Jeremy Allison 2001-2002, - * Copyright (C) Gerald Carter 2000-2003, + * Copyright (C) Gerald Carter 2000-2004, * Copyright (C) Tim Potter 2001-2002. * * This program is free software; you can redistribute it and/or modify @@ -312,6 +312,7 @@ void invalidate_printer_hnd_cache( char *printername ) for ( p=printers_list; p; p=p->next ) { if ( p->printer_type==PRINTER_HANDLE_IS_PRINTER + && p->printer_info && StrCaseCmp(p->dev.handlename, printername)==0) { DEBUG(10,("invalidating printer_info cache for handl:\n")); @@ -507,17 +508,19 @@ static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename) if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) ) continue; + /* ------ sharename ------ */ + fstrcpy(sname, lp_servicename(snum)); DEBUGADD(10, ("share: %s\n",sname)); - /* sharename */ if ( strequal(sname, aprinter) ) { found = True; break; } - /* printername */ + /* ------ printername ------ */ + printer = NULL; result = get_a_printer( NULL, &printer, 2, sname ); if ( !W_ERROR_IS_OK(result) ) { @@ -534,10 +537,8 @@ static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename) continue; } - /* FIXME!! not mb safe here */ printername++; - /* sharename */ if ( strequal(printername, aprinter) ) { found = True; } @@ -1188,6 +1189,12 @@ static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, siz ZERO_STRUCT( notify ); notify2_unpack_msg( ¬ify, &msg_tv, msg_ptr, msg_len ); msg_ptr += msg_len; + + /* we don't know if the change was from us or not so kill + any cached printer objects */ + + if ( notify.type == PRINTER_NOTIFY_TYPE ) + invalidate_printer_hnd_cache( notify.printer ); /* add to correct list in container */ @@ -4310,11 +4317,10 @@ static BOOL construct_printer_info_5(Printer_entry *print_hnd, PRINTER_INFO_5 *p static BOOL construct_printer_info_7(Printer_entry *print_hnd, PRINTER_INFO_7 *printer, int snum) { char *guid_str = NULL; - UUID_FLAT guid; + struct uuid guid; if (is_printer_published(print_hnd, snum, &guid)) { - asprintf(&guid_str, "{%s}", - smb_uuid_string_static(smb_uuid_unpack_static(guid))); + asprintf(&guid_str, "{%s}", smb_uuid_string_static(guid)); strupper_m(guid_str); init_unistr(&printer->guid, guid_str); printer->action = SPOOL_DS_PUBLISH; diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c index 77b9be99660..54cc0d61618 100644 --- a/source/rpc_server/srv_srvsvc_nt.c +++ b/source/rpc_server/srv_srvsvc_nt.c @@ -1886,8 +1886,21 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename)); unix_convert(filename, conn, NULL, &bad_path, &st); - fsp = open_file_shared(conn, filename, &st, SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action); + if (bad_path) { + DEBUG(3,("_srv_net_file_query_secdesc: bad pathname %s\n", filename)); + r_u->status = WERR_ACCESS_DENIED; + goto error_exit; + } + + if (!check_name(filename,conn)) { + DEBUG(3,("_srv_net_file_query_secdesc: can't access %s\n", filename)); + r_u->status = WERR_ACCESS_DENIED; + goto error_exit; + } + + fsp = open_file_shared(conn, filename, &st, SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, + &access_mode, &action); if (!fsp) { /* Perhaps it is a directory */ @@ -1989,9 +2002,22 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_ unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename)); unix_convert(filename, conn, NULL, &bad_path, &st); + if (bad_path) { + DEBUG(3,("_srv_net_file_set_secdesc: bad pathname %s\n", filename)); + r_u->status = WERR_ACCESS_DENIED; + goto error_exit; + } + + if (!check_name(filename,conn)) { + DEBUG(3,("_srv_net_file_set_secdesc: can't access %s\n", filename)); + r_u->status = WERR_ACCESS_DENIED; + goto error_exit; + } + - fsp = open_file_shared(conn, filename, &st, SET_OPEN_MODE(DOS_OPEN_RDWR), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action); + fsp = open_file_shared(conn, filename, &st, SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDWR), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, + &access_mode, &action); if (!fsp) { /* Perhaps it is a directory */ diff --git a/source/rpcclient/cmd_spoolss.c b/source/rpcclient/cmd_spoolss.c index f5a440c024c..38558ec3d47 100644 --- a/source/rpcclient/cmd_spoolss.c +++ b/source/rpcclient/cmd_spoolss.c @@ -314,7 +314,7 @@ static WERROR cmd_spoolss_enum_printers(struct cli_state *cli, return WERR_OK; } - if (argc == 2) + if (argc >= 2) info_level = atoi(argv[1]); if (argc == 3) @@ -547,6 +547,76 @@ static WERROR cmd_spoolss_setprinter(struct cli_state *cli, } /*********************************************************************** + * Set printer name - use a level2 set. + */ +static WERROR cmd_spoolss_setprintername(struct cli_state *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + WERROR result; + uint32 needed; + uint32 info_level = 2; + BOOL opened_hnd = False; + PRINTER_INFO_CTR ctr; + fstring printername, + servername, + user, + new_printername; + + if (argc == 1 || argc > 3) { + printf("Usage: %s printername new_printername\n", argv[0]); + + return WERR_OK; + } + + /* Open a printer handle */ + if (argc == 3) { + fstrcpy(new_printername, argv[2]); + } + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + fstrcpy(printername, argv[1]); + fstrcpy(user, cli->user_name); + + /* get a printer handle */ + result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", + PRINTER_ALL_ACCESS, servername, + user, &pol); + + if (!W_ERROR_IS_OK(result)) + goto done; + + opened_hnd = True; + + /* Get printer info */ + result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, info_level, &ctr); + + if (W_ERROR_V(result) == ERRinsufficientbuffer) + result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, info_level, &ctr); + + if (!W_ERROR_IS_OK(result)) + goto done; + + + /* Modify the printername. */ + init_unistr(&ctr.printers_2->printername, new_printername); + ctr.printers_2->devmode = NULL; + ctr.printers_2->secdesc = NULL; + + result = cli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0); + if (W_ERROR_IS_OK(result)) + printf("Success in setting printername.\n"); + + done: + if (opened_hnd) + cli_spoolss_close_printer(cli, mem_ctx, &pol); + + return result; +} + +/*********************************************************************** * Get printer information */ static WERROR cmd_spoolss_getprinter(struct cli_state *cli, @@ -1844,6 +1914,7 @@ static WERROR cmd_spoolss_setprinterdata(struct cli_state *cli, PRINTER_INFO_CTR ctr; PRINTER_INFO_0 info; REGISTRY_VALUE value; + UNISTR2 data; /* parse the command arguements */ if (argc != 4) { @@ -1881,10 +1952,11 @@ static WERROR cmd_spoolss_setprinterdata(struct cli_state *cli, /* Set the printer data */ + init_unistr2(&data, argv[3], UNI_STR_TERMINATE); fstrcpy(value.valuename, argv[2]); value.type = REG_SZ; - value.size = strlen(argv[3]) + 1; - value.data_p = talloc_memdup(mem_ctx, argv[3], value.size); + value.size = data.uni_str_len * 2; + value.data_p = talloc_memdup(mem_ctx, data.buffer, value.size); result = cli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value); @@ -2331,6 +2403,7 @@ struct cmd_set spoolss_commands[] = { { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, PI_SPOOLSS, "Delete form", "" }, { "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, PI_SPOOLSS, "Enumerate forms", "" }, { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, PI_SPOOLSS, "Set printer comment", "" }, + { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, PI_SPOOLSS, "Set printername", "" }, { "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, PI_SPOOLSS, "Set REG_SZ printer data", "" }, { "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, PI_SPOOLSS, "Rffpcnex test", "" }, diff --git a/source/sam/idmap.c b/source/sam/idmap.c index 4d8b768c2fa..bbb4980c766 100644 --- a/source/sam/idmap.c +++ b/source/sam/idmap.c @@ -36,6 +36,8 @@ static struct idmap_function_entry *backends = NULL; static struct idmap_methods *cache_map; static struct idmap_methods *remote_map; +static BOOL proxyonly = False; + /********************************************************************** Get idmap methods. Don't allow tdb to be a remote method. **********************************************************************/ @@ -144,6 +146,15 @@ BOOL idmap_init(const char *remote_backend) } /************************************************************************** + Don't do id mapping. This is used to make winbind a netlogon proxy only. +**************************************************************************/ + +void idmap_proxyonly(void) +{ + proxyonly = True; +} + +/************************************************************************** This is a rare operation, designed to allow an explicit mapping to be set up for a sid to a POSIX id. **************************************************************************/ @@ -153,6 +164,9 @@ NTSTATUS idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type) struct idmap_methods *map = remote_map; DOM_SID tmp_sid; + if (proxyonly) + return NT_STATUS_UNSUCCESSFUL; + DEBUG(10, ("idmap_set_mapping: Set %s to %s %lu\n", sid_string_static(sid), ((id_type & ID_TYPEMASK) == ID_USERID) ? "UID" : "GID", @@ -186,6 +200,9 @@ NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid) NTSTATUS ret; int loc_type; + if (proxyonly) + return NT_STATUS_UNSUCCESSFUL; + loc_type = *id_type; if (remote_map) { @@ -227,6 +244,9 @@ NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type) NTSTATUS ret; int loc_type; + if (proxyonly) + return NT_STATUS_UNSUCCESSFUL; + loc_type = id_type; if (remote_map) { loc_type = id_type | ID_QUERY_ONLY; @@ -260,6 +280,9 @@ NTSTATUS idmap_allocate_id(unid_t *id, int id_type) { /* we have to allocate from the authoritative backend */ + if (proxyonly) + return NT_STATUS_UNSUCCESSFUL; + if ( remote_map ) return remote_map->allocate_id( id, id_type ); @@ -274,6 +297,9 @@ NTSTATUS idmap_allocate_rid(uint32 *rid, int type) { /* we have to allocate from the authoritative backend */ + if (proxyonly) + return NT_STATUS_UNSUCCESSFUL; + if ( remote_map ) return remote_map->allocate_rid( rid, type ); @@ -288,6 +314,9 @@ NTSTATUS idmap_close(void) { NTSTATUS ret; + if (proxyonly) + return NT_STATUS_OK; + ret = cache_map->close(); if (!NT_STATUS_IS_OK(ret)) { DEBUG(3, ("idmap_close: failed to close local tdb cache!\n")); diff --git a/source/sam/idmap_ldap.c b/source/sam/idmap_ldap.c index 2124fb68793..d83c0bdc4d8 100644 --- a/source/sam/idmap_ldap.c +++ b/source/sam/idmap_ldap.c @@ -711,8 +711,12 @@ static NTSTATUS verify_idpool( void ) get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str ); smbldap_set_mod( &mods, LDAP_MOD_ADD, get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str ); - - rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods); + if (mods) { + rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods); + ldap_mods_free( mods, True ); + } else { + return NT_STATUS_UNSUCCESSFUL; + } } return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk index b38f405e0da..4c9507dcf9b 100644 --- a/source/script/mkproto.awk +++ b/source/script/mkproto.awk @@ -124,7 +124,7 @@ END { gotstart = 1; } - if( $0 ~ /^smb_iconv_t|^long|^char|^uint|^NTSTATUS|^WERROR|^CLI_POLICY_HND|^struct|^BOOL|^void|^time|^smb_shm_offset_t|^shm_offset_t|^FILE|^XFILE|^SMB_OFF_T|^size_t|^ssize_t|^SMB_BIG_UINT/ ) { + if( $0 ~ /^smb_iconv_t|^long|^char|^uint|^NTSTATUS|^WERROR|^CLI_POLICY_HND|^struct|^BOOL|^void|^time|^smb_shm_offset_t|^shm_offset_t|^FILE|^XFILE|^SMB_OFF_T|^size_t|^ssize_t|^SMB_BIG_UINT|^SMB_BIG_INT/ ) { gotstart = 1; } @@ -132,7 +132,7 @@ END { gotstart = 1; } - if( $0 ~ /^WINBINDD_PW|^WINBINDD_GR|^NT_PRINTER_INFO_LEVEL_2|^LOGIN_CACHE/ ) { + if( $0 ~ /^WINBINDD_PW|^WINBINDD_GR|^NT_PRINTER_INFO_LEVEL_2|^LOGIN_CACHE|^krb5_error_code|^LDAP/ ) { gotstart = 1; } diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c index c0512d5539b..3983a4cbdfb 100644 --- a/source/smbd/blocking.c +++ b/source/smbd/blocking.c @@ -680,7 +680,7 @@ void process_blocking_lock_queue(time_t t) continue; } - if(!set_current_service(conn,True)) { + if(!set_current_service(conn,SVAL(blr->inbuf,smb_flg),True)) { DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) )); /* * Remove the entry and return an error to the client. diff --git a/source/smbd/close.c b/source/smbd/close.c index 8b3010c1b2e..6de27746442 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. file closing Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 1992-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 @@ -105,6 +106,36 @@ static int close_filestruct(files_struct *fsp) } /**************************************************************************** + If any deferred opens are waiting on this close, notify them. +****************************************************************************/ + +static void notify_deferred_opens(files_struct *fsp) +{ + deferred_open_entry *de_array = NULL; + int num_de_entries, i; + pid_t mypid = sys_getpid(); + + if (!lp_defer_sharing_violations()) { + return; + } + + num_de_entries = get_deferred_opens(fsp->conn, fsp->dev, fsp->inode, &de_array); + for (i = 0; i < num_de_entries; i++) { + deferred_open_entry *entry = &de_array[i]; + if (entry->pid == mypid) { + /* + * We need to notify ourself to retry the open. + * Do this by finding the queued SMB record, moving it + * to the head of the queue and changing the wait time to zero. + */ + schedule_sharing_violation_open_smb_message(entry->mid); + } else { + send_deferred_open_retry_message(entry); + } + } +} + +/**************************************************************************** Close a file. If normal_close is 1 then this came from a normal SMBclose (or equivalent) @@ -177,6 +208,9 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) SAFE_FREE(share_entry); + /* Notify any deferred opens waiting on this close. */ + notify_deferred_opens(fsp); + /* * NT can set delete_on_close of the last open * reference to a file. diff --git a/source/smbd/conn.c b/source/smbd/conn.c index e083e144263..34e19a3ca6b 100644 --- a/source/smbd/conn.c +++ b/source/smbd/conn.c @@ -161,7 +161,7 @@ void conn_close_all(void) connection_struct *conn, *next; for (conn=Connections;conn;conn=next) { next=conn->next; - set_current_service(conn, True); + set_current_service(conn, 0, True); close_cnum(conn, conn->vuid); } } diff --git a/source/smbd/connection.c b/source/smbd/connection.c index a9ab1424615..5bb76eb3bd8 100644 --- a/source/smbd/connection.c +++ b/source/smbd/connection.c @@ -29,8 +29,8 @@ static TDB_CONTEXT *tdb; TDB_CONTEXT *conn_tdb_ctx(void) { if (!tdb) - tdb = tdb_open_ex(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, - O_RDWR | O_CREAT, 0644, smbd_tdb_log); + tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, + O_RDWR | O_CREAT, 0644); return tdb; } @@ -131,8 +131,8 @@ BOOL claim_connection(connection_struct *conn, const char *name,int max_connecti TDB_DATA kbuf, dbuf; if (!tdb) - tdb = tdb_open_ex(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, - O_RDWR | O_CREAT, 0644, smbd_tdb_log); + tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, + O_RDWR | O_CREAT, 0644); if (!tdb) return False; diff --git a/source/smbd/dir.c b/source/smbd/dir.c index 06ef23ab8cd..b88f687766d 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -763,7 +763,8 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_ return True; else fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action); + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, + &access_mode, &smb_action); if (!fsp) return False; diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index d7dc63bb2fd..33c75fffd53 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -182,6 +182,7 @@ static BOOL get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_S if ((errno != ENOTSUP) && (errno != ENOATTR) && (errno != EACCES)) { DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n", path, strerror(errno) )); + set_store_dos_attributes(SNUM(conn), False); } #endif return False; @@ -224,9 +225,21 @@ static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_ files_struct *fsp = NULL; BOOL ret = False; + if (!lp_store_dos_attributes(SNUM(conn))) { + return False; + } + snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK); if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) { if((errno != EPERM) && (errno != EACCES)) { + if (errno == ENOSYS +#if defined(ENOTSUP) + || errno == ENOTSUP) { +#else + ) { +#endif + set_store_dos_attributes(SNUM(conn), False); + } return False; } diff --git a/source/smbd/error.c b/source/smbd/error.c index 9c81d465e7a..d611e0ef873 100644 --- a/source/smbd/error.c +++ b/source/smbd/error.c @@ -29,6 +29,17 @@ NTSTATUS unix_ERR_ntstatus = NT_STATUS_OK; extern struct unix_error_map unix_dos_nt_errmap[]; /**************************************************************************** + Ensure we don't have any errors cached. +****************************************************************************/ + +void clear_cached_errors(void) +{ + unix_ERR_class = SMB_SUCCESS; + unix_ERR_code = 0; + unix_ERR_ntstatus = NT_STATUS_OK; +} + +/**************************************************************************** Create an error packet from a cached error. ****************************************************************************/ diff --git a/source/smbd/filename.c b/source/smbd/filename.c index 5e5f5726913..ab75d9c06ae 100644 --- a/source/smbd/filename.c +++ b/source/smbd/filename.c @@ -135,7 +135,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen if (SMB_VFS_STAT(conn,name,&st) == 0) { *pst = st; } - DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); + DEBUG(5,("conversion finished \"\" -> %s\n",name)); return(True); } @@ -237,6 +237,15 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen */ DEBUG(5,("Not a dir %s\n",start)); *end = '/'; + /* + * We need to return the fact that the intermediate + * name resolution failed. This is used to return an + * error of ERRbadpath rather than ERRbadfile. Some + * Windows applications depend on the difference between + * these two errors. + */ + errno = ENOTDIR; + *bad_path = True; return(False); } @@ -265,6 +274,9 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen if (end) pstrcpy(rest,end+1); + /* Reset errno so we can detect directory open errors. */ + errno = 0; + /* * Try to find this part of the path in the directory. */ @@ -292,6 +304,11 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen return(False); } + if (errno == ENOTDIR) { + *bad_path = True; + return(False); + } + /* * Just the last part of the name doesn't exist. * We may need to strupper() or strlower() it in case @@ -392,12 +409,11 @@ BOOL check_name(pstring name,connection_struct *conn) { BOOL ret = True; - errno = 0; - if (IS_VETO_PATH(conn, name)) { /* Is it not dot or dot dot. */ if (!((name[0] == '.') && (!name[1] || (name[1] == '.' && !name[2])))) { DEBUG(5,("file path name %s vetoed\n",name)); + errno = ENOENT; return False; } } @@ -416,13 +432,15 @@ BOOL check_name(pstring name,connection_struct *conn) if ( (SMB_VFS_LSTAT(conn,name,&statbuf) != -1) && (S_ISLNK(statbuf.st_mode)) ) { DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name)); + errno = EACCES; ret = False; } } #endif - if (!ret) + if (!ret) { DEBUG(5,("check_name on %s failed\n",name)); + } return(ret); } @@ -496,5 +514,6 @@ static BOOL scan_directory(const char *path, char *name, size_t maxlength, } CloseDir(cur_dir); + errno = ENOENT; return(False); } diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c index c4df84e76c7..dd9708356e7 100644 --- a/source/smbd/lanman.c +++ b/source/smbd/lanman.c @@ -1121,11 +1121,11 @@ static int fill_srv_info(struct srv_info_struct *service, switch (uLevel) { case 0: - push_ascii(p,service->name, 15, STR_TERMINATE); + push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE); break; case 1: - push_ascii(p,service->name,15, STR_TERMINATE); + push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE); SIVAL(p,18,service->type); SIVAL(p,22,PTR_DIFF(p2,baseaddr)); len += CopyAndAdvance(&p2,service->comment,&l2); diff --git a/source/smbd/mangle_hash.c b/source/smbd/mangle_hash.c index 7b8cbdbddba..d7239b82a79 100644 --- a/source/smbd/mangle_hash.c +++ b/source/smbd/mangle_hash.c @@ -546,8 +546,10 @@ static void cache_mangled_name( char *mangled_name, char *raw_name ) /* Fill the new cache entry, and add it to the cache. */ s1 = (char *)(new_entry + 1); s2 = (char *)&(s1[mangled_len + 1]); - safe_strcpy( s1, mangled_name, mangled_len ); - safe_strcpy( s2, raw_name, raw_len ); + memcpy( s1, mangled_name, mangled_len ); + s1[mangled_len] = '\0'; + memcpy( s2, raw_name, raw_len ); + s2[raw_len] = '\0'; ubi_cachePut( mangled_cache, i, new_entry, s1 ); } diff --git a/source/smbd/msdfs.c b/source/smbd/msdfs.c index c66f0477a84..6c132897f98 100644 --- a/source/smbd/msdfs.c +++ b/source/smbd/msdfs.c @@ -65,7 +65,7 @@ static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp) DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename)); /* rest is reqpath */ - check_path_syntax(pdp->reqpath, p+1); + check_path_syntax(pdp->reqpath, p+1,True); DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath)); return True; @@ -111,7 +111,7 @@ static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path* pdp) DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename)); /* rest is reqpath */ - check_path_syntax(pdp->reqpath, p+1); + check_path_syntax(pdp->reqpath, p+1,True); DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath)); return True; diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c index 1843c174bb5..5ff53f63007 100644 --- a/source/smbd/negprot.c +++ b/source/smbd/negprot.c @@ -401,8 +401,9 @@ protocol [LANMAN2.1] #define ARCH_WIN2K 0xC /* Win2K is like NT */ #define ARCH_OS2 0x14 /* Again OS/2 is like NT */ #define ARCH_SAMBA 0x20 +#define ARCH_CIFSFS 0x40 -#define ARCH_ALL 0x3F +#define ARCH_ALL 0x7F /* List of supported protocols, most desired first */ static const struct { @@ -413,6 +414,7 @@ static const struct { } supported_protocols[] = { {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1}, {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1}, + {"POSIX 2", "NT1", reply_nt1, PROTOCOL_NT1}, {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, @@ -460,7 +462,7 @@ int reply_negprot(connection_struct *conn, else if (strcsequal(p,"DOS LANMAN2.1")) arch &= ( ARCH_WFWG | ARCH_WIN95 ); else if (strcsequal(p,"NT LM 0.12")) - arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); + arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS); else if (strcsequal(p,"LANMAN2.1")) arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); else if (strcsequal(p,"LM1.2X002")) @@ -472,12 +474,23 @@ int reply_negprot(connection_struct *conn, else if (strcsequal(p,"Samba")) { arch = ARCH_SAMBA; break; + } else if (strcsequal(p,"POSIX 2")) { + arch = ARCH_CIFSFS; + break; } p += strlen(p) + 2; } - + + /* CIFSFS can send one arch only, NT LM 0.12. */ + if (Index == 1 && (arch & ARCH_CIFSFS)) { + arch = ARCH_CIFSFS; + } + switch ( arch ) { + case ARCH_CIFSFS: + set_remote_arch(RA_CIFSFS); + break; case ARCH_SAMBA: set_remote_arch(RA_SAMBA); break; diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c index ec414454f9e..843580f6edf 100644 --- a/source/smbd/notify_hash.c +++ b/source/smbd/notify_hash.c @@ -164,7 +164,7 @@ static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, if (!change_to_user(conn,vuid)) return True; - if (!set_current_service(conn,True)) { + if (!set_current_service(conn,FLAG_CASELESS_PATHNAMES,True)) { change_to_root_user(); return True; } diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 26be4434fdb..f717efac63e 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -651,7 +651,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib if(!dir_fsp->is_directory) { - srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status,False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBntcreateX); return ERROR_NT(status); @@ -693,14 +693,14 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib dir_name_len++; } - srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status,False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBntcreateX); return ERROR_NT(status); } pstrcat(fname, rel_fname); } else { - srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status,False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBntcreateX); return ERROR_NT(status); @@ -762,7 +762,18 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib set_posix_case_semantics(conn, file_attributes); unix_convert(fname,conn,0,&bad_path,&sbuf); - + if (bad_path) { + restore_case_semantics(conn, file_attributes); + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } + /* All file access must go through check_name() */ + if (!check_name(fname,conn)) { + restore_case_semantics(conn, file_attributes); + END_PROFILE(SMBntcreateX); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); + } + /* * If it's a request for a directory open, deal with it separately. */ @@ -863,6 +874,11 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } @@ -1010,7 +1026,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, cha return ERROR_DOS(ERRDOS,ERRnoaccess); } - srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -1213,7 +1229,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o return ERROR_DOS(ERRDOS,ERRbadfid); if(!dir_fsp->is_directory) { - srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -1246,14 +1262,14 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o { pstring tmpname; - srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status); + srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } pstrcat(fname, tmpname); } } else { - srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -1287,6 +1303,15 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + restore_case_semantics(conn, file_attributes); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } + /* All file access must go through check_name() */ + if (!check_name(fname,conn)) { + restore_case_semantics(conn, file_attributes); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); + } /* * If it's a request for a directory open, deal with it separately. @@ -1347,6 +1372,11 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o } } else { restore_case_semantics(conn, file_attributes); + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } @@ -1491,6 +1521,155 @@ int reply_ntcancel(connection_struct *conn, } /**************************************************************************** + Copy a file. +****************************************************************************/ + +static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *newname, uint16 attrs) +{ + BOOL bad_path_oldname = False; + BOOL bad_path_newname = False; + SMB_STRUCT_STAT sbuf1, sbuf2; + pstring last_component_oldname; + pstring last_component_newname; + files_struct *fsp1,*fsp2; + uint16 fmode; + int access_mode; + int smb_action; + SMB_OFF_T ret=-1; + int close_ret; + NTSTATUS status = NT_STATUS_OK; + + ZERO_STRUCT(sbuf1); + ZERO_STRUCT(sbuf2); + + /* No wildcards. */ + if (ms_has_wild(newname) || ms_has_wild(oldname)) { + return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; + } + + if (!CAN_WRITE(conn)) + return NT_STATUS_MEDIA_WRITE_PROTECTED; + + unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1); + if (bad_path_oldname) { + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + + /* Quick check for "." and ".." */ + if (last_component_oldname[0] == '.') { + if (!last_component_oldname[1] || (last_component_oldname[1] == '.' && !last_component_oldname[2])) { + return NT_STATUS_OBJECT_NAME_INVALID; + } + } + + /* Source must already exist. */ + if (!VALID_STAT(sbuf1)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + if (!check_name(oldname,conn)) { + return NT_STATUS_ACCESS_DENIED; + } + + /* Ensure attributes match. */ + fmode = dos_mode(conn,oldname,&sbuf1); + if ((fmode & ~attrs) & (aHIDDEN | aSYSTEM)) + return NT_STATUS_NO_SUCH_FILE; + + unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2); + if (bad_path_newname) { + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + + /* Quick check for "." and ".." */ + if (last_component_newname[0] == '.') { + if (!last_component_newname[1] || (last_component_newname[1] == '.' && !last_component_newname[2])) { + return NT_STATUS_OBJECT_NAME_INVALID; + } + } + + /* Disallow if newname already exists. */ + if (VALID_STAT(sbuf2)) { + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + if (!check_name(newname,conn)) { + return NT_STATUS_ACCESS_DENIED; + } + + /* No links from a directory. */ + if (S_ISDIR(sbuf1.st_mode)) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + /* Ensure this is within the share. */ + if (!reduce_name(conn, oldname) != 0) { + return NT_STATUS_ACCESS_DENIED; + } + + DEBUG(10,("copy_internals: doing file copy %s to %s\n", oldname, newname)); + + fsp1 = open_file_shared1(conn,oldname,&sbuf1,FILE_READ_DATA,SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_RDONLY), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,0, + &access_mode,&smb_action); + + if (!fsp1) { + status = NT_STATUS_ACCESS_DENIED; + if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare) + status = NT_STATUS_SHARING_VIOLATION; + unix_ERR_class = 0; + unix_ERR_code = 0; + unix_ERR_ntstatus = NT_STATUS_OK; + return status; + } + + fsp2 = open_file_shared1(conn,newname,&sbuf2,FILE_WRITE_DATA,SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_WRONLY), + (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL),fmode,INTERNAL_OPEN_ONLY, + &access_mode,&smb_action); + + if (!fsp2) { + status = NT_STATUS_ACCESS_DENIED; + if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare) + status = NT_STATUS_SHARING_VIOLATION; + unix_ERR_class = 0; + unix_ERR_code = 0; + unix_ERR_ntstatus = NT_STATUS_OK; + close_file(fsp1,False); + return status; + } + + if (sbuf1.st_size) + ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size); + + /* + * As we are opening fsp1 read-only we only expect + * an error on close on fsp2 if we are out of space. + * Thus we don't look at the error return from the + * close of fsp1. + */ + close_file(fsp1,False); + + /* Ensure the modtime is set correctly on the destination file. */ + fsp2->pending_modtime = sbuf1.st_mtime; + + close_ret = close_file(fsp2,False); + + /* Grrr. We have to do this as open_file_shared1 adds aARCH when it + creates the file. This isn't the correct thing to do in the copy case. JRA */ + file_set_dosmode(conn, newname, fmode, &sbuf2); + + if (ret < (SMB_OFF_T)sbuf1.st_size) { + return NT_STATUS_DISK_FULL; + } + + if (close_ret != 0) { + status = map_nt_error_from_unix(close_ret); + DEBUG(3,("copy_internals: Error %s copy file %s to %s\n", + nt_errstr(status), oldname, newname)); + } + return status; +} + +/**************************************************************************** Reply to a NT rename request. ****************************************************************************/ @@ -1507,13 +1686,8 @@ int reply_ntrename(connection_struct *conn, START_PROFILE(SMBntrename); - if ((rename_type != RENAME_FLAG_RENAME) && (rename_type != RENAME_FLAG_HARD_LINK)) { - END_PROFILE(SMBntrename); - return ERROR_NT(NT_STATUS_ACCESS_DENIED); - } - p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status); + p += srvstr_get_path(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, True); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBntrename); return ERROR_NT(status); @@ -1525,8 +1699,13 @@ int reply_ntrename(connection_struct *conn, return ERROR_NT(NT_STATUS_ACCESS_DENIED); } + if (ms_has_wild(oldname)) { + END_PROFILE(SMBntrename); + return ERROR_NT(NT_STATUS_OBJECT_PATH_SYNTAX_BAD); + } + p++; - p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status); + p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBntrename); return ERROR_NT(status); @@ -1537,14 +1716,31 @@ int reply_ntrename(connection_struct *conn, DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname)); - if (rename_type == RENAME_FLAG_RENAME) { - status = rename_internals(conn, oldname, newname, attrs, False); - } else { - status = hardlink_internals(conn, oldname, newname); + switch(rename_type) { + case RENAME_FLAG_RENAME: + status = rename_internals(conn, oldname, newname, attrs, False); + break; + case RENAME_FLAG_HARD_LINK: + status = hardlink_internals(conn, oldname, newname); + break; + case RENAME_FLAG_COPY: + status = copy_internals(conn, oldname, newname, attrs); + break; + case RENAME_FLAG_MOVE_CLUSTER_INFORMATION: + status = NT_STATUS_INVALID_PARAMETER; + break; + default: + status = NT_STATUS_ACCESS_DENIED; /* Default error. */ + break; } if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBntrename); + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return ERROR_NT(status); } @@ -1630,7 +1826,7 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o fsp = file_fsp(params, 0); replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; CHECK_FSP(fsp, conn); - srvstr_get_path(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status, True); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } diff --git a/source/smbd/open.c b/source/smbd/open.c index 3b4f50b0656..65500c65cee 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. file opening and share modes Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Jeremy Allison 2001 + Copyright (C) Jeremy Allison 2001-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 @@ -26,6 +26,11 @@ extern uint16 global_oplock_port; extern uint16 global_smbpid; extern BOOL global_client_failed_oplock_break; +struct dev_inode_bundle { + SMB_DEV_T dev; + SMB_INO_T inode; +}; + /**************************************************************************** fd support routines - attempt to do a dos_open. ****************************************************************************/ @@ -239,11 +244,12 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), conn->num_files_open + 1)); + errno = 0; return True; } /******************************************************************* -return True if the filename is one of the special executable types + Return True if the filename is one of the special executable types. ********************************************************************/ static BOOL is_executable(const char *fname) @@ -262,12 +268,13 @@ static BOOL is_executable(const char *fname) enum {AFAIL,AREAD,AWRITE,AALL}; /******************************************************************* -reproduce the share mode access table -this is horrendoously complex, and really can't be justified on any -rational grounds except that this is _exactly_ what NT does. See -the DENY1 and DENY2 tests in smbtorture for a comprehensive set of -test routines. + Reproduce the share mode access table. + This is horrendoously complex, and really can't be justified on any + rational grounds except that this is _exactly_ what NT does. See + the DENY1 and DENY2 tests in smbtorture for a comprehensive set of + test routines. ********************************************************************/ + static int access_table(int new_deny,int old_deny,int old_mode, BOOL same_pid, BOOL isexe) { @@ -353,9 +360,8 @@ static int access_table(int new_deny,int old_deny,int old_mode, return(AFAIL); } - /**************************************************************************** -check if we can open a file with a share mode + Check if we can open a file with a share mode. ****************************************************************************/ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode, uint32 desired_access, @@ -364,6 +370,8 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i int deny_mode = GET_DENY_MODE(share_mode); int old_open_mode = GET_OPEN_MODE(share->share_mode); int old_deny_mode = GET_DENY_MODE(share->share_mode); + BOOL non_io_open_request; + BOOL non_io_open_existing; /* * share modes = false means don't bother to check for @@ -373,6 +381,18 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i if(!lp_share_modes(SNUM(conn))) return True; + if (desired_access & ~(SYNCHRONIZE_ACCESS|READ_CONTROL_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) { + non_io_open_request = False; + } else { + non_io_open_request = True; + } + + if (share->desired_access & ~(SYNCHRONIZE_ACCESS|READ_CONTROL_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) { + non_io_open_existing = False; + } else { + non_io_open_existing = True; + } + /* * Don't allow any opens once the delete on close flag has been * set. @@ -411,8 +431,7 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i * and the existing desired_acces then share modes don't conflict. */ - if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) && - !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) { + if (non_io_open_request && non_io_open_existing) { /* * Wrinkle discovered by smbtorture.... @@ -436,6 +455,13 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i and existing desired access (0x%x) are non-data opens\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); return True; + } else if (non_io_open_request || non_io_open_existing) { + /* + * If either are non-io opens then share modes don't conflict. + */ + DEBUG(5,("check_share_mode: One non-io open. Allowing open on file %s as desired access (0x%x) doesn't conflict with\ +existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); + return True; } /* @@ -537,6 +563,20 @@ static void validate_my_share_entries(int num, share_mode_entry *share_entry) } #endif +struct share_mode_entry_list { + struct share_mode_entry_list *next, *prev; + share_mode_entry entry; +}; + +static void free_broken_entry_list(struct share_mode_entry_list *broken_entry_list) +{ + while (broken_entry_list) { + struct share_mode_entry_list *broken_entry = broken_entry_list; + DLIST_REMOVE(broken_entry_list, broken_entry); + SAFE_FREE(broken_entry); + } +} + /**************************************************************************** Deal with open deny mode and oplock break processing. Invarient: Share mode must be locked on entry and exit. @@ -554,8 +594,8 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T int oplock_contention_count = 0; share_mode_entry *old_shares = 0; BOOL fcbopen = False; - BOOL broke_oplock; - + BOOL broke_oplock; + if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB) fcbopen = True; @@ -564,17 +604,25 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T if(num_share_modes == 0) return 0; + if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) && + ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) { + /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */ + return num_share_modes; + } + /* * Check if the share modes will give us access. */ do { - share_mode_entry broken_entry; - + struct share_mode_entry_list *broken_entry_list = NULL; + struct share_mode_entry_list *broken_entry = NULL; + broke_oplock = False; *p_all_current_opens_are_level_II = True; for(i = 0; i < num_share_modes; i++) { + BOOL cause_oplock_break = False; share_mode_entry *share_entry = &old_shares[i]; #if defined(DEVELOPER) @@ -589,9 +637,17 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T * it before continuing. */ - if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) || + /* Was this a delete this file request ? */ + if (!*p_oplock_request && desired_access == DELETE_ACCESS && + !BATCH_OPLOCK_TYPE(share_entry->op_type)) { + /* Don't break the oplock in this case. */ + cause_oplock_break = False; + } else if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) || (!*p_oplock_request && (share_entry->op_type != NO_OPLOCK))) { - + cause_oplock_break = True; + } + + if(cause_oplock_break) { BOOL opb_ret; DEBUG(5,("open_mode_check: oplock_request = %d, breaking oplock (%x) on file %s, \ @@ -622,50 +678,65 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou return -1; } + broken_entry = malloc(sizeof(struct share_mode_entry_list)); + if (!broken_entry) { + smb_panic("open_mode_check: malloc fail.\n"); + } + broken_entry->entry = *share_entry; + DLIST_ADD(broken_entry_list, broken_entry); broke_oplock = True; - broken_entry = *share_entry; - break; } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { *p_all_current_opens_are_level_II = False; } - + } /* end for */ + + if (broke_oplock) { + /* Update the current open table. */ + SAFE_FREE(old_shares); + num_share_modes = get_share_modes(conn, dev, inode, &old_shares); + } + + /* Now we check the share modes, after any oplock breaks. */ + for(i = 0; i < num_share_modes; i++) { + share_mode_entry *share_entry = &old_shares[i]; + /* someone else has a share lock on it, check to see if we can too */ if (!check_share_mode(conn, share_entry, share_mode, desired_access, fname, fcbopen, p_flags)) { SAFE_FREE(old_shares); + free_broken_entry_list(broken_entry_list); errno = EACCES; return -1; } - - } /* end for */ - - if(broke_oplock) { - SAFE_FREE(old_shares); - num_share_modes = get_share_modes(conn, dev, inode, &old_shares); + } + + for(broken_entry = broken_entry_list; broken_entry; broken_entry = broken_entry->next) { oplock_contention_count++; /* Paranoia check that this is no longer an exlusive entry. */ for(i = 0; i < num_share_modes; i++) { share_mode_entry *share_entry = &old_shares[i]; - if (share_modes_identical(&broken_entry, share_entry) && - EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) { + if (share_modes_identical(&broken_entry->entry, share_entry) && + EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) { /* * This should not happen. The target left this oplock * as exlusive.... The process *must* be dead.... */ - DEBUG(0,("open_mode_check: exlusive oplock left by process %d after break ! For file %s, \ -dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fname, (unsigned int)dev, (double)inode)); + DEBUG(0,("open_mode_check: exlusive oplock left by process %d \ +after break ! For file %s, dev = %x, inode = %.0f. Deleting it to continue...\n", + (int)broken_entry->entry.pid, fname, (unsigned int)dev, (double)inode)); - if (process_exists(broken_entry.pid)) { + if (process_exists(broken_entry->entry.pid)) { DEBUG(0,("open_mode_check: Existent process %lu left active oplock.\n", - (unsigned long)broken_entry.pid )); + (unsigned long)broken_entry->entry.pid )); } - if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) { + if (del_share_entry(dev, inode, &broken_entry->entry, NULL) == -1) { + free_broken_entry_list(broken_entry_list); errno = EACCES; unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; @@ -683,8 +754,8 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn break; } } /* end for paranoia... */ - } /* end if broke_oplock */ - + } /* end for broken_entry */ + free_broken_entry_list(broken_entry_list); } while(broke_oplock); if(old_shares != 0) @@ -705,9 +776,119 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn } /**************************************************************************** -set a kernel flock on a file for NFS interoperability -this requires a patch to Linux + Delete the record for a handled deferred open entry. ****************************************************************************/ + +static void delete_defered_open_entry_record(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode) +{ + uint16 mid = get_current_mid(); + pid_t mypid = sys_getpid(); + deferred_open_entry *de_array = NULL; + int num_de_entries, i; + + if (!lp_defer_sharing_violations()) { + return; + } + + num_de_entries = get_deferred_opens(conn, dev, inode, &de_array); + for (i = 0; i < num_de_entries; i++) { + deferred_open_entry *entry = &de_array[i]; + if (entry->pid == mypid && entry->mid == mid && entry->dev == dev && + entry->inode == inode) { + + /* Remove the deferred open entry from the array. */ + delete_deferred_open_entry(entry); + SAFE_FREE(de_array); + return; + } + } + SAFE_FREE(de_array); +} + +/**************************************************************************** + Handle the 1 second delay in returning a SHARING_VIOLATION error. +****************************************************************************/ + +void defer_open_sharing_error(connection_struct *conn, struct timeval *ptv, + char *fname, SMB_DEV_T dev, SMB_INO_T inode) +{ + uint16 mid = get_current_mid(); + pid_t mypid = sys_getpid(); + deferred_open_entry *de_array = NULL; + int num_de_entries, i; + struct dev_inode_bundle dib; + + if (!lp_defer_sharing_violations()) { + return; + } + + dib.dev = dev; + dib.inode = inode; + + num_de_entries = get_deferred_opens(conn, dev, inode, &de_array); + for (i = 0; i < num_de_entries; i++) { + deferred_open_entry *entry = &de_array[i]; + if (entry->pid == mypid && entry->mid == mid) { + /* + * Check if a 1 second timeout has expired. + */ + if (usec_time_diff(ptv, &entry->time) > SHARING_VIOLATION_USEC_WAIT) { + DEBUG(10,("defer_open_sharing_error: Deleting deferred open entry for mid %u, \ +file %s\n", + (unsigned int)mid, fname )); + + /* Expired, return a real error. */ + /* Remove the deferred open entry from the array. */ + + delete_deferred_open_entry(entry); + SAFE_FREE(de_array); + return; + } + /* + * If the timeout hasn't expired yet and we still have a sharing violation, + * just leave the entry in the deferred open array alone. We do need to + * reschedule this open call though (with the original created time). + */ + DEBUG(10,("defer_open_sharing_error: time [%u.%06u] updating \ +deferred open entry for mid %u, file %s\n", + (unsigned int)entry->time.tv_sec, + (unsigned int)entry->time.tv_usec, + (unsigned int)mid, fname )); + + push_sharing_violation_open_smb_message(&entry->time, (char *)&dib, sizeof(dib)); + SAFE_FREE(de_array); + return; + } + } + + DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred open entry for mid %u, file %s\n", + (unsigned int)ptv->tv_sec, (unsigned int)ptv->tv_usec, (unsigned int)mid, fname )); + + if (!push_sharing_violation_open_smb_message(ptv, (char *)&dib, sizeof(dib))) { + SAFE_FREE(de_array); + return; + } + if (!add_deferred_open(mid, ptv, dev, inode, global_oplock_port, fname)) { + remove_sharing_violation_open_smb_message(mid); + } + + /* + * Push the MID of this packet on the signing queue. + * We only do this once, the first time we push the packet + * onto the deferred open queue, as this has a side effect + * of incrementing the response sequence number. + */ + + srv_defer_sign_response(mid); + + SAFE_FREE(de_array); +} + +/**************************************************************************** + Set a kernel flock on a file for NFS interoperability. + This requires a patch to Linux. +****************************************************************************/ + static void kernel_flock(files_struct *fsp, int deny_mode) { #if HAVE_KERNEL_SHARE_MODES @@ -781,6 +962,8 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ BOOL file_existed = VALID_STAT(*psbuf); BOOL fcbopen = False; BOOL def_acl = False; + BOOL add_share_mode = True; + BOOL internal_only_open = False; SMB_DEV_T dev = 0; SMB_INO_T inode = 0; int num_share_modes = 0; @@ -792,9 +975,50 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ mode_t new_mode = (mode_t)0; int action; uint32 existing_dos_mode = 0; + struct pending_message_list *pml = NULL; + uint16 mid = get_current_mid(); /* We add aARCH to this as this mode is only used if the file is created new. */ mode_t mode = unix_mode(conn,new_dos_mode | aARCH,fname); + if (oplock_request == INTERNAL_OPEN_ONLY) { + internal_only_open = True; + oplock_request = 0; + } + + if ((pml = get_open_deferred_message(mid)) != NULL) { + struct dev_inode_bundle dib; + + memcpy(&dib, pml->private_data.data, sizeof(dib)); + + /* There could be a race condition where the dev/inode pair + has changed since we deferred the message. If so, just + remove the deferred open entry and return sharing violation. */ + + /* If the timeout value is non-zero, we need to just + return sharing violation. Don't retry the open + as we were not notified of a close and we don't want to + trigger another spurious oplock break. */ + + if (!file_existed || dib.dev != psbuf->st_dev || dib.inode != psbuf->st_ino || + pml->msg_time.tv_sec || pml->msg_time.tv_usec) { + /* Ensure we don't reprocess this message. */ + remove_sharing_violation_open_smb_message(mid); + + /* Now remove the deferred open entry under lock. */ + lock_share_entry(conn, dib.dev, dib.inode); + delete_defered_open_entry_record(conn, dib.dev, dib.inode); + unlock_share_entry(conn, dib.dev, dib.inode); + + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadshare; + unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; + return NULL; + } + /* Ensure we don't reprocess this message. */ + remove_sharing_violation_open_smb_message(mid); + + } + if (conn->printer) { /* printers are handled completely differently. Most of the passed parameters are ignored */ @@ -805,25 +1029,6 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ return print_fsp_open(conn, fname); } - if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) && - ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) { - /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */ - oplock_request = 0; - fsp = open_file_stat(conn, fname, psbuf); - if (!fsp) - return NULL; - - fsp->desired_access = desired_access; - if (Access) - *Access = DOS_OPEN_RDONLY; - if (paction) - *paction = FILE_WAS_OPENED; - - DEBUG(10,("open_file_shared: stat open for fname = %s share_mode = %x\n", - fname, share_mode )); - return fsp; - } - fsp = file_new(conn); if(!fsp) return NULL; @@ -947,6 +1152,17 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ return NULL; } + if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) && + ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) { + /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */ + deny_mode = DENY_NONE; + if (file_existed) { + oplock_request = 0; + add_share_mode = False; + flags2 &= ~O_CREAT; + } + } + if (file_existed) { dev = psbuf->st_dev; @@ -985,17 +1201,28 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", unix_ERR_ntstatus = NT_STATUS_ACCESS_DENIED; } + /* + * If we're returning a share violation, ensure we cope with + * the braindead 1 second delay. + */ + + if (!internal_only_open && NT_STATUS_EQUAL(unix_ERR_ntstatus,NT_STATUS_SHARING_VIOLATION)) { + /* The fsp->open_time here represents the current time of day. */ + defer_open_sharing_error(conn, &fsp->open_time, fname, dev, inode); + } + unlock_share_entry(conn, dev, inode); - if (fsp_open) + if (fsp_open) { fd_close(conn, fsp); + /* + * We have detected a sharing violation here + * so return the correct error code + */ + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadshare; + unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; + } file_free(fsp); - /* - * We have detected a sharing violation here - * so return the correct error code - */ - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return NULL; } @@ -1060,6 +1287,16 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", &flags, &oplock_request, &all_current_opens_are_level_II); if(num_share_modes == -1) { + /* + * If we're returning a share violation, ensure we cope with + * the braindead 1 second delay. + */ + + if (!internal_only_open && NT_STATUS_EQUAL(unix_ERR_ntstatus,NT_STATUS_SHARING_VIOLATION)) { + /* The fsp->open_time here represents the current time of day. */ + defer_open_sharing_error(conn, &fsp->open_time, fname, dev, inode); + } + unlock_share_entry_fsp(fsp); fd_close(conn,fsp); file_free(fsp); @@ -1166,14 +1403,18 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", oplock_request = 0; } - set_share_mode(fsp, port, oplock_request); + if (add_share_mode) { + set_share_mode(fsp, port, oplock_request); + } if (delete_on_close) { NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close); if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) { /* Remember to delete the mode we just added. */ - del_share_mode(fsp, NULL); + if (add_share_mode) { + del_share_mode(fsp, NULL); + } unlock_share_entry_fsp(fsp); fd_close(conn,fsp); file_free(fsp); @@ -1224,6 +1465,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", fname, (int)new_mode)); } + /* If this is a successful open, we must remove any deferred open records. */ + delete_defered_open_entry_record(conn, fsp->dev, fsp->inode); unlock_share_entry_fsp(fsp); conn->num_files_open++; diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 19e6956d9ef..1ffc798b1fc 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -388,6 +388,30 @@ pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n", (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id)); break; + case RETRY_DEFERRED_OPEN_CMD: + + /* Request to retry and open that would return SHARING_VIOLATION. */ + if (msg_len != DEFERRED_OPEN_MSG_LEN) { + DEBUG(0,("process_local_message: incorrect length for RETRY_DEFERRED_OPEN_CMD (was %d, should be %d).\n", + (int)msg_len, (int)DEFERRED_OPEN_MSG_LEN)); + return False; + } + { + uint16 mid; + + memcpy((char *)&remotepid, msg_start+DEFERRED_OPEN_PID_OFFSET,sizeof(remotepid)); + memcpy((char *)&inode, msg_start+DEFERRED_OPEN_INODE_OFFSET,sizeof(inode)); + memcpy((char *)&dev, msg_start+DEFERRED_OPEN_DEV_OFFSET,sizeof(dev)); + memcpy((char *)&mid, msg_start+DEFERRED_OPEN_MID_OFFSET,sizeof(mid)); + + DEBUG(5,("process_local_message: RETRY_DEFERRED_OPEN from \ +pid %d, port %d, dev = %x, inode = %.0f, mid = %u\n", + (int)remotepid, from_port, (unsigned int)dev, (double)inode, (unsigned int)mid)); + + schedule_sharing_violation_open_smb_message(mid); + } + return True; + /* * Keep this as a debug case - eventually we can remove it. */ @@ -592,6 +616,8 @@ BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token) */ if (global_client_caps & CAP_LEVEL_II_OPLOCKS) { + BOOL sign_state; + /* * If we are sending an oplock break due to an SMB sent * by our own client we ensure that we wait at leat @@ -603,10 +629,16 @@ BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token) wait_before_sending_break(local_request); /* Prepare the SMBlockingX message. */ - prepare_break_message( outbuf, fsp, False); + + /* Save the server smb signing state. */ + sign_state = srv_oplock_set_signing(False); + if (!send_smb(smbd_server_fd(), outbuf)) exit_server("oplock_break_level2: send_smb failed."); + + /* Restore the sign state to what it was. */ + srv_oplock_set_signing(sign_state); } /* @@ -1215,7 +1247,51 @@ void release_level_2_oplocks_on_change(files_struct *fsp) } /**************************************************************************** -setup oplocks for this process + Send a 'retry your open' message to a process with a deferred open entry. +****************************************************************************/ + +BOOL send_deferred_open_retry_message(deferred_open_entry *entry) +{ + char de_msg[DEFERRED_OPEN_MSG_LEN]; + struct sockaddr_in addr_out; + pid_t pid = sys_getpid(); + + memset(de_msg, '\0', DEFERRED_OPEN_MSG_LEN); + SSVAL(de_msg,DEFERRED_OPEN_CMD_OFFSET,RETRY_DEFERRED_OPEN_CMD); + memcpy(de_msg+DEFERRED_OPEN_PID_OFFSET,(char *)&pid,sizeof(pid)); + memcpy(de_msg+DEFERRED_OPEN_DEV_OFFSET,(char *)&entry->dev,sizeof(entry->dev)); + memcpy(de_msg+DEFERRED_OPEN_INODE_OFFSET,(char *)&entry->inode,sizeof(entry->inode)); + memcpy(de_msg+DEFERRED_OPEN_MID_OFFSET,(char *)&entry->mid,sizeof(entry->mid)); + + /* Set the address and port. */ + memset((char *)&addr_out,'\0',sizeof(addr_out)); + addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr_out.sin_port = htons( entry->port ); + addr_out.sin_family = AF_INET; + + if( DEBUGLVL( 3 ) ) { + dbgtext( "send_deferred_open_retry_message: sending a message to "); + dbgtext( "pid %d on port %d ", (int)entry->pid, entry->port ); + dbgtext( "for dev = %x, inode = %.0f, mid = %u\n", + (unsigned int)entry->dev, (double)entry->inode, (unsigned int)entry->mid ); + } + + if(sys_sendto(oplock_sock,de_msg,DEFERRED_OPEN_MSG_LEN,0, + (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) { + if( DEBUGLVL( 0 ) ) { + dbgtext( "send_deferred_open_retry_message: failed sending a message to "); + dbgtext( "pid %d on port %d ", (int)entry->pid, entry->port ); + dbgtext( "for dev = %x, inode = %.0f, mid = %u\n", + (unsigned int)entry->dev, (double)entry->inode, (unsigned int)entry->mid ); + dbgtext( "Error was %s\n", strerror(errno) ); + } + return False; + } + return True; +} + +/**************************************************************************** + Setup oplocks for this process. ****************************************************************************/ BOOL init_oplocks(void) diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 584164e9309..2d9591e6baa 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -880,7 +880,7 @@ static mode_t map_nt_perms( SEC_ACCESS sec_access, int type) Unpack a SEC_DESC into a UNIX owner and group. ****************************************************************************/ -static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd) +static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd) { DOM_SID owner_sid; DOM_SID grp_sid; @@ -910,15 +910,17 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, if (security_info_sent & OWNER_SECURITY_INFORMATION) { sid_copy(&owner_sid, psd->owner_sid); if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) { -#if ACL_FORCE_UNMAPPABLE - /* this allows take ownership to work reasonably */ - extern struct current_user current_user; - *puser = current_user.uid; -#else - DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n", - sid_string_static(&owner_sid))); - return False; -#endif + if (lp_force_unknown_acl_user(snum)) { + /* this allows take ownership to work + * reasonably */ + extern struct current_user current_user; + *puser = current_user.uid; + } else { + DEBUG(3,("unpack_nt_owners: unable to validate" + " owner sid for %s\n", + sid_string_static(&owner_sid))); + return False; + } } } @@ -930,14 +932,16 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, if (security_info_sent & GROUP_SECURITY_INFORMATION) { sid_copy(&grp_sid, psd->grp_sid); if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) { -#if ACL_FORCE_UNMAPPABLE - /* this allows take group ownership to work reasonably */ - extern struct current_user current_user; - *pgrp = current_user.gid; -#else - DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n")); - return False; -#endif + if (lp_force_unknown_acl_user(snum)) { + /* this allows take group ownership to work + * reasonably */ + extern struct current_user current_user; + *pgrp = current_user.gid; + } else { + DEBUG(3,("unpack_nt_owners: unable to validate" + " group sid.\n")); + return False; + } } } @@ -3005,7 +3009,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) * Unpack the user/group/world id's. */ - if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd)) + if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd)) return False; /* diff --git a/source/smbd/process.c b/source/smbd/process.c index 12fd809b784..60ce1499e8d 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -61,55 +61,215 @@ uint16 get_current_mid(void) for processing. ****************************************************************************/ -typedef struct { - ubi_slNode msg_next; - char *msg_buf; - int msg_len; -} pending_message_list; +static struct pending_message_list *smb_oplock_queue; +static struct pending_message_list *smb_sharing_violation_queue; -static ubi_slList smb_oplock_queue = { NULL, (ubi_slNodePtr)&smb_oplock_queue, 0}; +enum q_type { OPLOCK_QUEUE, SHARE_VIOLATION_QUEUE }; + +/**************************************************************************** + Free up a message. +****************************************************************************/ + +static void free_queued_message(struct pending_message_list *msg) +{ + data_blob_free(&msg->buf); + data_blob_free(&msg->private_data); + SAFE_FREE(msg); +} /**************************************************************************** Function to push a message onto the tail of a linked list of smb messages ready for processing. ****************************************************************************/ -static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len) +static BOOL push_queued_message(enum q_type qt, char *buf, int msg_len, struct timeval *ptv, char *private, size_t private_len) { - pending_message_list *msg = (pending_message_list *) - malloc(sizeof(pending_message_list)); + struct pending_message_list *tmp_msg; + struct pending_message_list *msg = (struct pending_message_list *) + malloc(sizeof(struct pending_message_list)); if(msg == NULL) { DEBUG(0,("push_message: malloc fail (1)\n")); return False; } - msg->msg_buf = (char *)malloc(msg_len); - if(msg->msg_buf == NULL) { + memset(msg,'\0',sizeof(*msg)); + + msg->buf = data_blob(buf, msg_len); + if(msg->buf.data == NULL) { DEBUG(0,("push_message: malloc fail (2)\n")); SAFE_FREE(msg); return False; } - memcpy(msg->msg_buf, buf, msg_len); - msg->msg_len = msg_len; + if (ptv) { + msg->msg_time = *ptv; + } + + if (private) { + msg->private_data = data_blob(private, private_len); + if (msg->private_data.data == NULL) { + DEBUG(0,("push_message: malloc fail (3)\n")); + data_blob_free(&msg->buf); + SAFE_FREE(msg); + } + } - ubi_slAddTail( list_head, msg); + if (qt == OPLOCK_QUEUE) { + DLIST_ADD_END(smb_oplock_queue, msg, tmp_msg); + } else { + DLIST_ADD_END(smb_sharing_violation_queue, msg, tmp_msg); + } - /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(buf,smb_mid)); + DEBUG(10,("push_message: pushed message length %u on queue %s\n", + (unsigned int)msg_len, + qt == OPLOCK_QUEUE ? "smb_oplock_queue" : "smb_sharing_violation_queue" )); return True; } /**************************************************************************** - Function to push a smb message onto a linked list of local smb messages ready + Function to push an oplock smb message onto a linked list of local smb messages ready for processing. ****************************************************************************/ BOOL push_oplock_pending_smb_message(char *buf, int msg_len) { - return push_message(&smb_oplock_queue, buf, msg_len); + BOOL ret = push_queued_message(OPLOCK_QUEUE, buf, msg_len, NULL, NULL, 0); + if (ret) { + /* Push the MID of this packet on the signing queue. */ + srv_defer_sign_response(SVAL(buf,smb_mid)); + } + return ret; +} + +/**************************************************************************** + Function to delete a sharing violation open message by mid. +****************************************************************************/ + +void remove_sharing_violation_open_smb_message(uint16 mid) +{ + struct pending_message_list *pml; + + if (!lp_defer_sharing_violations()) { + return; + } + + for (pml = smb_sharing_violation_queue; pml; pml = pml->next) { + if (mid == SVAL(pml->buf.data,smb_mid)) { + DEBUG(10,("remove_sharing_violation_open_smb_message: deleting mid %u len %u\n", + (unsigned int)mid, (unsigned int)pml->buf.length )); + DLIST_REMOVE(smb_sharing_violation_queue, pml); + free_queued_message(pml); + return; + } + } +} + +/**************************************************************************** + Move a sharing violation open retry message to the front of the list and + schedule it for immediate processing. +****************************************************************************/ + +void schedule_sharing_violation_open_smb_message(uint16 mid) +{ + struct pending_message_list *pml; + int i = 0; + + if (!lp_defer_sharing_violations()) { + return; + } + + for (pml = smb_sharing_violation_queue; pml; pml = pml->next) { + uint16 msg_mid = SVAL(pml->buf.data,smb_mid); + DEBUG(10,("schedule_sharing_violation_open_smb_message: [%d] msg_mid = %u\n", i++, + (unsigned int)msg_mid )); + if (mid == msg_mid) { + DEBUG(10,("schedule_sharing_violation_open_smb_message: scheduling mid %u\n", + mid )); + pml->msg_time.tv_sec = 0; + pml->msg_time.tv_usec = 0; + DLIST_PROMOTE(smb_sharing_violation_queue, pml); + return; + } + } + + DEBUG(10,("schedule_sharing_violation_open_smb_message: failed to find message mid %u\n", + mid )); +} + +/**************************************************************************** + Return true if this mid is on the deferred queue. +****************************************************************************/ + +BOOL open_was_deferred(uint16 mid) +{ + struct pending_message_list *pml; + + if (!lp_defer_sharing_violations()) { + return False; + } + + for (pml = smb_sharing_violation_queue; pml; pml = pml->next) { + if (SVAL(pml->buf.data,smb_mid) == mid) { + return True; + } + } + return False; +} + +/**************************************************************************** + Return the message queued by this mid. +****************************************************************************/ + +struct pending_message_list *get_open_deferred_message(uint16 mid) +{ + struct pending_message_list *pml; + + if (!lp_defer_sharing_violations()) { + return NULL; + } + + for (pml = smb_sharing_violation_queue; pml; pml = pml->next) { + if (SVAL(pml->buf.data,smb_mid) == mid) { + return pml; + } + } + return NULL; +} + +/**************************************************************************** + Function to push a sharing violation open smb message onto a linked list of local smb messages ready + for processing. +****************************************************************************/ + +BOOL push_sharing_violation_open_smb_message(struct timeval *ptv, char *private, size_t priv_len) +{ + uint16 mid = SVAL(InBuffer,smb_mid); + struct timeval tv; + SMB_BIG_INT tdif; + + if (!lp_defer_sharing_violations()) { + return True; + } + + tv = *ptv; + tdif = tv.tv_sec; + tdif *= 1000000; + tdif += tv.tv_usec; + + /* Add on the timeout. */ + tdif += SHARING_VIOLATION_USEC_WAIT; + + tv.tv_sec = tdif / 1000000; + tv.tv_usec = tdif % 1000000; + + DEBUG(10,("push_sharing_violation_open_smb_message: pushing message len %u mid %u\ + timeout time [%u.%06u]\n", (unsigned int) smb_len(InBuffer)+4, (unsigned int)mid, + (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec)); + + return push_queued_message(SHARE_VIOLATION_QUEUE, InBuffer, + smb_len(InBuffer)+4, &tv, private, priv_len); } /**************************************************************************** @@ -168,12 +328,17 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) fd_set fds; int selrtn; struct timeval to; + struct timeval *pto; int maxfd; smb_read_error = 0; again: + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout % 1000) * 1000; + pto = timeout > 0 ? &to : NULL; + /* * Note that this call must be before processing any SMB * messages as we need to synchronously process any messages @@ -185,18 +350,57 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) * Check to see if we already have a message on the smb queue. * If so - copy and return it. */ - if(ubi_slCount(&smb_oplock_queue) != 0) { - pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue); - memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len)); + if(smb_oplock_queue != NULL) { + struct pending_message_list *msg = smb_oplock_queue; + memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length)); /* Free the message we just copied. */ - SAFE_FREE(msg->msg_buf); - SAFE_FREE(msg); + DLIST_REMOVE(smb_oplock_queue, msg); + free_queued_message(msg); DEBUG(5,("receive_message_or_smb: returning queued smb message.\n")); return True; } + /* + * Check to see if we already have a message on the deferred open queue + * and it's time to schedule. + */ + if(smb_sharing_violation_queue != NULL) { + BOOL pop_message = False; + struct pending_message_list *msg = smb_sharing_violation_queue; + + if (msg->msg_time.tv_sec == 0 && msg->msg_time.tv_usec == 0) { + pop_message = True; + } else { + struct timeval tv; + SMB_BIG_INT tdif; + + GetTimeOfDay(&tv); + tdif = usec_time_diff(&msg->msg_time, &tv); + if (tdif <= 0) { + /* Timed out. Schedule...*/ + pop_message = True; + DEBUG(10,("receive_message_or_smb: queued message timed out.\n")); + } else { + /* Make a more accurate select timeout. */ + to.tv_sec = tdif / 1000000; + to.tv_usec = tdif % 1000000; + pto = &to; + DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n", + (unsigned int)pto->tv_sec, (unsigned int)pto->tv_usec )); + } + } + + if (pop_message) { + memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length)); + + /* We leave this message on the queue so the open code can + know this is a retry. */ + DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n")); + return True; + } + } /* * Setup the select read fd set. @@ -227,10 +431,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) FD_SET(smbd_server_fd(),&fds); maxfd = setup_oplock_select_set(&fds); - to.tv_sec = timeout / 1000; - to.tv_usec = (timeout % 1000) * 1000; - - selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,timeout>0?&to:NULL); + selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,pto); /* if we get EINTR then maybe we have received an oplock signal - treat this as select returning 1. This is ugly, but @@ -755,7 +956,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize return(ERROR_DOS(ERRSRV,ERRaccess)); /* load service specific parameters */ - if (conn && !set_current_service(conn,(flags & (AS_USER|DO_CHDIR)?True:False))) + if (conn && !set_current_service(conn,SVAL(inbuf,smb_flg),(flags & (AS_USER|DO_CHDIR)?True:False))) return(ERROR_DOS(ERRSRV,ERRaccess)); /* does this protocol need to be run as guest? */ diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c index e439c1e571a..3c4d4319f63 100644 --- a/source/smbd/quotas.c +++ b/source/smbd/quotas.c @@ -933,6 +933,176 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB #include #endif +#if defined(__FreeBSD__) + +#include +#include +#include +#include +#include + +static int quotastat; + +static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args) +{ + if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN )) + return(0); + if (!xdr_int(xdrsp, &args->gqa_uid)) + return(0); + return (1); +} + +static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr) +{ + if (!xdr_int(xdrsp, "astat)) { + DEBUG(6,("nfs_quotas: Status bad or zero\n")); + return 0; + } + if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) { + DEBUG(6,("nfs_quotas: Block size bad or zero\n")); + return 0; + } + if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) { + DEBUG(6,("nfs_quotas: Active bad or zero\n")); + return 0; + } + if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) { + DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n")); + return 0; + } + if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) { + DEBUG(6,("nfs_quotas: Softlimit bad or zero\n")); + return 0; + } + if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) { + DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n")); + return 0; + } + return (1); +} + +/* Works on FreeBSD, too. :-) */ +static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +{ + uid_t uid = euser_id; + struct dqblk D; + char *mnttype = nfspath; + CLIENT *clnt; + struct getquota_rslt gqr; + struct getquota_args args; + char *cutstr, *pathname, *host, *testpath; + int len; + static struct timeval timeout = {2,0}; + enum clnt_stat clnt_stat; + BOOL ret = True; + + *bsize = *dfree = *dsize = (SMB_BIG_UINT)0; + + len=strcspn(mnttype, ":"); + pathname=strstr(mnttype, ":"); + cutstr = (char *) malloc(len+1); + if (!cutstr) + return False; + + memset(cutstr, '\0', len+1); + host = strncat(cutstr,mnttype, sizeof(char) * len ); + DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr)); + DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype)); + testpath=strchr_m(mnttype, ':'); + args.gqa_pathp = testpath+1; + args.gqa_uid = uid; + + DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp")); + + if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) { + ret = False; + goto out; + } + + clnt->cl_auth = authunix_create_default(); + DEBUG(9,("nfs_quotas: auth_success\n")); + + clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout); + + if (clnt_stat != RPC_SUCCESS) { + DEBUG(9,("nfs_quotas: clnt_call fail\n")); + ret = False; + goto out; + } + + /* + * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is + * no quota set, and 3 if no permission to get the quota. If 0 or 3 return + * something sensible. + */ + + switch ( quotastat ) { + case 0: + DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat )); + ret = False; + goto out; + + case 1: + DEBUG(9,("nfs_quotas: Good quota data\n")); + D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit; + D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit; + D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks; + break; + + case 2: + case 3: + D.dqb_bsoftlimit = 1; + D.dqb_curblocks = 1; + DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat )); + break; + + default: + DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat )); + break; + } + + DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n", + quotastat, + gqr.getquota_rslt_u.gqr_rquota.rq_bsize, + gqr.getquota_rslt_u.gqr_rquota.rq_active, + gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit, + gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit, + gqr.getquota_rslt_u.gqr_rquota.rq_curblocks)); + + if (D.dqb_bsoftlimit == 0) + D.dqb_bsoftlimit = D.dqb_bhardlimit; + if (D.dqb_bsoftlimit == 0) + return False; + + *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize; + *dsize = D.dqb_bsoftlimit; + + if (D.dqb_curblocks == D.dqb_curblocks == 1) + *bsize = DEV_BSIZE; + + if (D.dqb_curblocks > D.dqb_bsoftlimit) { + *dfree = 0; + *dsize = D.dqb_curblocks; + } else + *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; + + out: + + if (clnt) { + if (clnt->cl_auth) + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + } + + DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize)); + + SAFE_FREE(cutstr); + DEBUG(10,("nfs_quotas: End of nfs_quotas\n" )); + return ret; +} + +#endif + /**************************************************************************** try to get the disk space from disk quotas - default version ****************************************************************************/ @@ -976,10 +1146,42 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB { /* FreeBSD patches from Marty Moll */ gid_t egrp_id; - +#if defined(__FreeBSD__) + SMB_DEV_T devno; + struct statfs *mnts; + SMB_STRUCT_STAT st; + int mntsize, i; + + if (sys_stat(path,&st) < 0) + return False; + devno = st.st_dev; + + mntsize = getmntinfo(&mnts,MNT_NOWAIT); + if (mntsize <= 0) + return False; + + for (i = 0; i < mntsize; i++) { + if (sys_stat(mnts[i].f_mntonname,&st) < 0) + return False; + if (st.st_dev == devno) + break; + } + if (i == mntsize) + return False; +#endif + save_re_uid(); set_effective_uid(0); +#if defined(__FreeBSD__) + if (strcmp(mnts[i].f_fstypename,"nfs") == 0) { + BOOL retval; + retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize); + restore_re_uid(); + return retval; + } +#endif + egrp_id = getegid(); r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D); diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 560208ae157..71efb793af0 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -43,7 +43,7 @@ extern BOOL global_encrypted_passwords_negotiated; set. ****************************************************************************/ -NTSTATUS check_path_syntax(pstring destname, const pstring srcname) +NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_wcard_names) { char *d = destname; const char *s = srcname; @@ -119,7 +119,21 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname) s++; } else { if (!(*s & 0x80)) { - *d++ = *s++; + if (allow_wcard_names) { + *d++ = *s++; + } else { + switch (*s) { + case '*': + case '?': + case '<': + case '>': + case '"': + return NT_STATUS_OBJECT_NAME_INVALID; + default: + *d++ = *s++; + break; + } + } } else { switch(next_mb_char_size(s)) { case 4: @@ -147,7 +161,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname) Pull a string and check the path - provide for error return. ****************************************************************************/ -size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err) +size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err, BOOL allow_wcard_names) { pstring tmppath; char *tmppath_ptr = tmppath; @@ -161,7 +175,7 @@ size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len } else { ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags); } - *err = check_path_syntax(dest, tmppath); + *err = check_path_syntax(dest, tmppath, allow_wcard_names); return ret; } @@ -516,7 +530,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size START_PROFILE(SMBchkpth); - srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBchkpth); return ERROR_NT(status); @@ -525,6 +539,10 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size RESOLVE_DFSPATH(name, conn, inbuf, outbuf); unix_convert(name,conn,0,&bad_path,&sbuf); + if (bad_path) { + END_PROFILE(SMBchkpth); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } mode = SVAL(inbuf,smb_vwv0); @@ -548,18 +566,11 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size * the parent directory is valid but not the * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND - * if the path is invalid. + * if the path is invalid. This is different from set_bad_path_error() + * in the non-NT error case. */ - if (bad_path) { - END_PROFILE(SMBchkpth); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } else { - END_PROFILE(SMBchkpth); - return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND); - } - } else if (errno == ENOTDIR) { END_PROFILE(SMBchkpth); - return ERROR_NT(NT_STATUS_NOT_A_DIRECTORY); + return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath); } END_PROFILE(SMBchkpth); @@ -594,7 +605,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size START_PROFILE(SMBgetatr); p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status); + p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBgetatr); return ERROR_NT(status); @@ -613,6 +624,10 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size ok = True; } else { unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + END_PROFILE(SMBgetatr); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } if (check_name(fname,conn)) { if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) { mode = dos_mode(conn,fname,&sbuf); @@ -669,13 +684,17 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size START_PROFILE(SMBsetatr); p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status); + p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBsetatr); return ERROR_NT(status); } unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + END_PROFILE(SMBsetatr); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } mode = SVAL(inbuf,smb_vwv0); mtime = make_unix_date3(inbuf+smb_vwv1); @@ -798,7 +817,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size maxentries = SVAL(inbuf,smb_vwv0); dirtype = SVAL(inbuf,smb_vwv1); p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status); + p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status, True); if (!NT_STATUS_IS_OK(nt_status)) { END_PROFILE(SMBsearch); return ERROR_NT(nt_status); @@ -976,7 +995,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size outsize = set_message(outbuf,1,0,True); p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err); + p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err, True); if (!NT_STATUS_IS_OK(err)) { END_PROFILE(SMBfclose); return ERROR_NT(err); @@ -1028,7 +1047,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, share_mode = SVAL(inbuf,smb_vwv0); - srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBopen); return ERROR_NT(status); @@ -1037,12 +1056,21 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + END_PROFILE(SMBopen); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), (uint32)dos_attr, oplock_request,&rmode,NULL); if (!fsp) { END_PROFILE(SMBopen); + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } @@ -1117,7 +1145,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt } /* XXXX we need to handle passed times, sattr and flags */ - srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBopenX); return ERROR_NT(status); @@ -1126,12 +1154,21 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + END_PROFILE(SMBopenX); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,(uint32)smb_attr, oplock_request, &rmode,&smb_action); if (!fsp) { END_PROFILE(SMBopenX); + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } @@ -1230,7 +1267,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, com = SVAL(inbuf,smb_com); createmode = SVAL(inbuf,smb_vwv0); - srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcreate); return ERROR_NT(status); @@ -1239,6 +1276,10 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + END_PROFILE(SMBcreate); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } if (createmode & aVOLID) DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname)); @@ -1257,6 +1298,11 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (!fsp) { END_PROFILE(SMBcreate); + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } @@ -1297,7 +1343,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, START_PROFILE(SMBctemp); createattr = SVAL(inbuf,smb_vwv0); - srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBctemp); return ERROR_NT(status); @@ -1311,6 +1357,10 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + END_PROFILE(SMBctemp); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } tmpfd = smb_mkstemp(fname); if (tmpfd == -1) { @@ -1332,6 +1382,11 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (!fsp) { END_PROFILE(SMBctemp); + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } @@ -1373,15 +1428,20 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, Check if a user is allowed to rename a file. ********************************************************************/ -static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst) +static NTSTATUS can_rename(char *fname,connection_struct *conn, uint16 dirtype, SMB_STRUCT_STAT *pst) { int smb_action; int access_mode; files_struct *fsp; + uint16 fmode; if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED; - + + fmode = dos_mode(conn,fname,pst); + if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) + return NT_STATUS_NO_SUCH_FILE; + if (S_ISDIR(pst->st_mode)) return NT_STATUS_OK; @@ -1561,7 +1621,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) /* Quick check for "." and ".." */ if (fname[0] == '.') { if (!fname[1] || (fname[1] == '.' && !fname[2])) { - if ((dirtype & aDIR)) { + if ((dirtype & FILE_ATTRIBUTE_DIRECTORY) && (dirtype & FILE_ATTRIBUTE_SYSTEM)) { sys_direntry = True; } else { continue; @@ -1574,6 +1634,8 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) if (sys_direntry) { error = NT_STATUS_OBJECT_NAME_INVALID; + DEBUG(3,("unlink_internals: system directory delete denied [%s] mask [%s]\n", + fname, mask)); break; } @@ -1612,7 +1674,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size dirtype = SVAL(inbuf,smb_vwv0); - srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status, True); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBunlink); return ERROR_NT(status); @@ -1623,8 +1685,14 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size DEBUG(3,("reply_unlink : %s\n",name)); status = unlink_internals(conn, dirtype, name); - if (!NT_STATUS_IS_OK(status)) + if (!NT_STATUS_IS_OK(status)) { + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return ERROR_NT(status); + } /* * Win2k needs a changenotify request response before it will @@ -1661,12 +1729,13 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st #if defined(WITH_SENDFILE) /* - * We can only use sendfile on a non-chained packet and on a file - * that is exclusively oplocked. reply_readbraw has already checked the length. + * We can only use sendfile on a non-chained packet + * but we can use on a non-oplocked file. tridge proved this + * on a train in Germany :-). JRA. + * reply_readbraw has already checked the length. */ - if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) && - EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && lp_use_sendfile(SNUM(conn)) ) { + if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) && lp_use_sendfile(SNUM(conn)) ) { DATA_BLOB header; _smb_setlen(outbuf,nread); @@ -1999,12 +2068,13 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length #if defined(WITH_SENDFILE) /* - * We can only use sendfile on a non-chained packet and on a file - * that is exclusively oplocked. + * We can only use sendfile on a non-chained packet + * but we can use on a non-oplocked file. tridge proved this + * on a train in Germany :-). JRA. */ - if ((CVAL(inbuf,smb_vwv0) == 0xFF) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && - lp_use_sendfile(SNUM(conn)) && (lp_write_cache_size(SNUM(conn)) == 0) ) { + if ((CVAL(inbuf,smb_vwv0) == 0xFF) && lp_use_sendfile(SNUM(conn)) && + (lp_write_cache_size(SNUM(conn)) == 0) ) { SMB_STRUCT_STAT sbuf; DATA_BLOB header; @@ -3138,15 +3208,16 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) return NT_STATUS_OBJECT_NAME_INVALID; } + if (bad_path) { + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + if (check_name(directory, conn)) ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory)); if (ret == -1) { if(errno == ENOENT) { - if (bad_path) - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - else - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } return map_nt_error_from_unix(errno); } @@ -3165,7 +3236,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, NTSTATUS status; START_PROFILE(SMBmkdir); - srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmkdir); return ERROR_NT(status); @@ -3335,7 +3406,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, NTSTATUS status; START_PROFILE(SMBrmdir); - srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBrmdir); return ERROR_NT(status); @@ -3344,6 +3415,10 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(directory, conn, inbuf, outbuf) unix_convert(directory,conn, NULL,&bad_path,&sbuf); + if (bad_path) { + END_PROFILE(SMBrmdir); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } if (check_name(directory,conn)) { dptr_closepath(directory,SVAL(inbuf,smb_pid)); @@ -3475,7 +3550,7 @@ static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T Rename an open file - given an fsp. ****************************************************************************/ -NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, BOOL replace_if_exists) +NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, uint16 attrs, BOOL replace_if_exists) { SMB_STRUCT_STAT sbuf; BOOL bad_path = False; @@ -3556,7 +3631,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char * return NT_STATUS_OBJECT_NAME_COLLISION; } - error = can_rename(newname,conn,&sbuf); + error = can_rename(newname,conn,attrs,&sbuf); if (dest_exists && !NT_STATUS_IS_OK(error)) { DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", @@ -3762,7 +3837,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", return NT_STATUS_OBJECT_PATH_NOT_FOUND; } - error = can_rename(directory,conn,&sbuf1); + error = can_rename(directory,conn,attrs,&sbuf1); if (!NT_STATUS_IS_OK(error)) { DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", @@ -3853,7 +3928,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error))); continue; } - error = can_rename(fname,conn,&sbuf1); + error = can_rename(fname,conn,attrs,&sbuf1); if (!NT_STATUS_IS_OK(error)) { DEBUG(6,("rename %s refused\n", fname)); continue; @@ -3924,13 +3999,13 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, START_PROFILE(SMBmv); p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status); + p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, True); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmv); return ERROR_NT(status); } p++; - p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status); + p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, True); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmv); return ERROR_NT(status); @@ -3944,6 +4019,11 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, status = rename_internals(conn, name, newname, attrs, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmv); + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return ERROR_NT(status); } @@ -3989,7 +4069,8 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, return(False); fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,0,&Access,&action); + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,INTERNAL_OPEN_ONLY, + &Access,&action); if (!fsp1) return(False); @@ -4002,7 +4083,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, ZERO_STRUCTP(&sbuf2); fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY), - ofun,dosattrs,0,&Access,&action); + ofun,dosattrs,INTERNAL_OPEN_ONLY,&Access,&action); if (!fsp2) { close_file(fsp1,False); @@ -4070,12 +4151,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, *directory = *mask = 0; p = smb_buf(inbuf); - p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status); + p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, True); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcopy); return ERROR_NT(status); } - p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status); + p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, True); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcopy); return ERROR_NT(status); @@ -4235,7 +4316,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_DOS(ERRDOS,ERRnoaccess); } - srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status); + srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(pathworks_setdir); return ERROR_NT(status); diff --git a/source/smbd/server.c b/source/smbd/server.c index 343a835be8a..c3e0da542e2 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -494,18 +494,16 @@ BOOL reload_services(BOOL test) load_interfaces(); - { - if (smbd_server_fd() != -1) { - set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); - set_socket_options(smbd_server_fd(), user_socket_options); - } + if (smbd_server_fd() != -1) { + set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); + set_socket_options(smbd_server_fd(), user_socket_options); } mangle_reset_cache(); reset_stat_cache(); /* this forces service parameters to be flushed */ - set_current_service(NULL,True); + set_current_service(NULL,0,True); return(ret); } diff --git a/source/smbd/service.c b/source/smbd/service.c index c74537c299e..3b499d5cc1d 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -28,10 +28,11 @@ extern userdom_struct current_user_info; Load parameters specific to a connection/service. ****************************************************************************/ -BOOL set_current_service(connection_struct *conn,BOOL do_chdir) +BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir) { extern char magic_char; static connection_struct *last_conn; + static uint16 last_flags; int snum; if (!conn) { @@ -51,10 +52,24 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir) return(False); } - if (conn == last_conn) + if ((conn == last_conn) && (last_flags == flags)) { return(True); + } last_conn = conn; + last_flags = flags; + + /* Obey the client case sensitivity requests - only for clients that support it. */ + if (lp_casesensitive(snum) == Auto) { + /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */ + enum remote_arch_types ra_type = get_remote_arch(); + if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) { + /* Client can't support per-packet case sensitive pathnames. */ + conn->case_sensitive = False; + } else { + conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES); + } + } magic_char = lp_magicchar(snum); return(True); @@ -347,7 +362,13 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->dirptr = NULL; /* Case options for the share. */ - conn->case_sensitive = lp_casesensitive(snum); + if (lp_casesensitive(snum) == Auto) { + /* We will be setting this per packet. Set to be case insensitive for now. */ + conn->case_sensitive = False; + } else { + conn->case_sensitive = (BOOL)lp_casesensitive(snum); + } + conn->case_preserve = lp_preservecase(snum); conn->short_case_preserve = lp_shortpreservecase(snum); @@ -499,6 +520,20 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return NULL; } + /* + * If widelinks are disallowed we need to canonicalise the + * connect path here to ensure we don't have any symlinks in + * the connectpath. We will be checking all paths on this + * connection are below this directory. We must do this after + * the VFS init as we depend on the realpath() pointer in the vfs table. JRA. + */ + if (!lp_widelinks(snum)) { + pstring s; + pstrcpy(s,conn->connectpath); + canonicalize_path(conn, s); + string_set(&conn->connectpath,s); + } + /* ROOT Activities: */ /* check number of connections */ if (!claim_connection(conn, diff --git a/source/smbd/session.c b/source/smbd/session.c index 61118f13dd9..91ebaeb830b 100644 --- a/source/smbd/session.c +++ b/source/smbd/session.c @@ -34,8 +34,8 @@ BOOL session_init(void) if (tdb) return True; - tdb = tdb_open_ex(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, - O_RDWR | O_CREAT, 0644, smbd_tdb_log); + tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, + O_RDWR | O_CREAT, 0644); if (!tdb) { DEBUG(1,("session_init: failed to open sessionid tdb\n")); return False; diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c index 8a56478929f..0122b662ebf 100644 --- a/source/smbd/sesssetup.c +++ b/source/smbd/sesssetup.c @@ -152,7 +152,6 @@ static int reply_spnego_kerberos(connection_struct *conn, auth_serversupplied_info *server_info = NULL; DATA_BLOB session_key = data_blob(NULL, 0); uint8 tok_id[2]; - BOOL foreign = False; DATA_BLOB nullblob = data_blob(NULL, 0); fstring real_username; @@ -197,7 +196,6 @@ static int reply_spnego_kerberos(connection_struct *conn, SAFE_FREE(client); return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - foreign = True; } /* this gives a fully qualified user name (ie. with full realm). @@ -244,6 +242,8 @@ static int reply_spnego_kerberos(connection_struct *conn, /* lookup the passwd struct, create a new user if necessary */ + map_username( user ); + pw = smb_getpwnam( user, real_username, True ); if (!pw) { diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 738d12e020f..a7db9daf7d6 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -607,7 +607,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i if (IS_IPC(conn)) return(ERROR_DOS(ERRSRV,ERRaccess)); - srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -618,6 +618,9 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i /* XXXX we need to handle passed times, sattr and flags */ unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } if (!check_name(fname,conn)) { return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); @@ -627,6 +630,11 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i oplock_request, &rmode,&smb_action); if (!fsp) { + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + clear_cached_errors(); + return -1; + } return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } @@ -1371,7 +1379,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", return(ERROR_DOS(ERRDOS,ERRunknownlevel)); } - srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus); + srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True); if (!NT_STATUS_IS_OK(ntstatus)) { return ERROR_NT(ntstatus); } @@ -1379,6 +1387,9 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf); unix_convert(directory,conn,0,&bad_path,&sbuf); + if (bad_path) { + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } if(!check_name(directory,conn)) { return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } @@ -1564,7 +1575,7 @@ static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbu *mask = *directory = *resume_name = 0; - srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus); + srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus, True); if (!NT_STATUS_IS_OK(ntstatus)) { return ERROR_NT(ntstatus); } @@ -2257,6 +2268,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, if (!params) return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + ZERO_STRUCT(sbuf); + if (tran_call == TRANSACT2_QFILEINFO) { if (total_params < 4) return(ERROR_DOS(ERRDOS,ERRinvalidparam)); @@ -2272,11 +2285,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, */ pstrcpy(fname, fsp->fsp_name); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } + /* We know this name is ok, it's already passed the checks. */ } else if(fsp && (fsp->is_directory || fsp->fd == -1)) { /* @@ -2284,12 +2293,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, * handle (returned from an NT SMB). NT5.0 seems * to do this call. JRA. */ + /* We know this name is ok, it's already passed the checks. */ pstrcpy(fname, fsp->fsp_name); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ @@ -2297,7 +2302,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } - } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) { + } else if (SMB_VFS_STAT(conn,fname,&sbuf)) { DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } @@ -2329,7 +2334,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); - srvstr_get_path(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -2337,6 +2342,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } if (!check_name(fname,conn)) { DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); @@ -2871,7 +2879,6 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam BOOL bad_path_oldname = False; BOOL bad_path_newname = False; SMB_STRUCT_STAT sbuf1, sbuf2; - BOOL rc, rcdest; pstring last_component_oldname; pstring last_component_newname; NTSTATUS status = NT_STATUS_OK; @@ -2884,8 +2891,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } - rc = unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1); - if (!rc && bad_path_oldname) { + unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1); + if (bad_path_oldname) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; } @@ -2905,8 +2912,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam return NT_STATUS_ACCESS_DENIED; } - rcdest = unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2); - if (!rcdest && bad_path_newname) { + unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2); + if (bad_path_newname) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; } @@ -2974,6 +2981,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, if (!params) return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + ZERO_STRUCT(sbuf); + if (tran_call == TRANSACT2_SETFILEINFO) { if (total_params < 4) return(ERROR_DOS(ERRDOS,ERRinvalidparam)); @@ -2988,8 +2997,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, * to do this call. JRA. */ pstrcpy(fname, fsp->fsp_name); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) { + if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } @@ -3027,11 +3035,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn, return(ERROR_DOS(ERRDOS,ERRinvalidparam)); info_level = SVAL(params,0); - srvstr_get_path(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } unix_convert(fname,conn,0,&bad_path,&sbuf); + if (bad_path) { + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } /* * For CIFS UNIX extensions the target name may not exist. @@ -3205,7 +3216,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, SET_OPEN_MODE(DOS_OPEN_RDWR), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, - 0, &access_mode, &action); + INTERNAL_OPEN_ONLY, &access_mode, &action); if (new_fsp == NULL) return(UNIXERROR(ERRDOS,ERRbadpath)); @@ -3374,14 +3385,15 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", return(ERROR_DOS(ERRDOS,ERRnoaccess)); if (file_type != UNIX_TYPE_CHARDEV && file_type != UNIX_TYPE_BLKDEV && - file_type != UNIX_TYPE_FIFO) + file_type != UNIX_TYPE_FIFO && + file_type != UNIX_TYPE_SOCKET) return(ERROR_DOS(ERRDOS,ERRnoaccess)); DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \ 0%o for file %s\n", (double)dev, unixmode, fname )); /* Ok - do the mknod. */ - if (SMB_VFS_MKNOD(conn,dos_to_unix_static(fname), unixmode, dev) != 0) + if (SMB_VFS_MKNOD(conn,fname, unixmode, dev) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); inherit_access_acl(conn, fname, unixmode); @@ -3482,7 +3494,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", char *newname = fname; /* Set a hard link. */ - srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -3515,7 +3527,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", overwrite = (CVAL(pdata,0) ? True : False); root_fid = IVAL(pdata,4); len = IVAL(pdata,8); - srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status); + srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -3538,7 +3550,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", if (fsp) { DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", fsp->fnum, fsp->fsp_name, base_name )); - status = rename_internals_fsp(conn, fsp, base_name, overwrite); + status = rename_internals_fsp(conn, fsp, base_name, 0, overwrite); } else { DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION %s -> %s\n", fname, newname )); @@ -3654,7 +3666,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", SET_OPEN_MODE(DOS_OPEN_RDWR), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, - 0, &access_mode, &action); + INTERNAL_OPEN_ONLY, &access_mode, &action); if (new_fsp == NULL) return(UNIXERROR(ERRDOS,ERRbadpath)); @@ -3695,7 +3707,7 @@ static int call_trans2mkdir(connection_struct *conn, if (total_params < 4) return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - srvstr_get_path(inbuf, directory, ¶ms[4], sizeof(directory), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, directory, ¶ms[4], sizeof(directory), -1, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -3703,6 +3715,9 @@ static int call_trans2mkdir(connection_struct *conn, DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); unix_convert(directory,conn,0,&bad_path,&sbuf); + if (bad_path) { + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } if (check_name(directory,conn)) ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory)); diff --git a/source/smbd/uid.c b/source/smbd/uid.c index e1864c74caa..de2f96450fc 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -125,6 +125,13 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) readonly_share = is_share_read_only_for_user(conn, vuser); + if (!readonly_share && + !share_access_check(conn, snum, vuser, FILE_WRITE_DATA)) { + /* smb.conf allows r/w, but the security descriptor denies + * write. Fall back to looking at readonly. */ + readonly_share = True; + } + if (!share_access_check(conn, snum, vuser, readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) { return False; } diff --git a/source/smbd/utmp.c b/source/smbd/utmp.c index a521d0113d4..b1735dfcc49 100644 --- a/source/smbd/utmp.c +++ b/source/smbd/utmp.c @@ -514,10 +514,10 @@ static BOOL sys_utmp_fill(struct utmp *u, * But note that we do the more precise ut_tv as the final assignment. */ #if defined(HAVE_UT_UT_TIME) - gettimeofday(&timeval, NULL); + GetTimeOfDay(&timeval); u->ut_time = timeval.tv_sec; #elif defined(HAVE_UT_UT_TV) - gettimeofday(&timeval, NULL); + GetTimeOfDay(&timeval); u->ut_tv = timeval; #else #error "with-utmp must have UT_TIME or UT_TV" diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c index a415e0470e2..13cfdac0f35 100644 --- a/source/smbd/vfs.c +++ b/source/smbd/vfs.c @@ -784,6 +784,31 @@ char *vfs_GetWd(connection_struct *conn, char *path) return (path); } +BOOL canonicalize_path(connection_struct *conn, pstring path) +{ +#ifdef REALPATH_TAKES_NULL + char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL); + if (!resolved_name) { + return False; + } + pstrcpy(path, resolved_name); + SAFE_FREE(resolved_name); + return True; +#else +#ifdef PATH_MAX + char resolved_name_buf[PATH_MAX+1]; +#else + pstring resolved_name_buf; +#endif + char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf); + if (!resolved_name) { + return False; + } + pstrcpy(path, resolved_name); + return True; +#endif /* REALPATH_TAKES_NULL */ +} + /******************************************************************* Reduce a file name, removing .. elements and checking that it is below dir in the heirachy. This uses realpath. @@ -804,6 +829,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname) char *resolved_name = NULL; size_t con_path_len = strlen(conn->connectpath); char *p = NULL; + int saved_errno = errno; DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath)); @@ -817,6 +843,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname) switch (errno) { case ENOTDIR: DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname)); + errno = saved_errno; return False; case ENOENT: { @@ -841,6 +868,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname) #endif if (!resolved_name) { DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname)); + errno = saved_errno; return False; } pstrcpy(tmp_fname, resolved_name); @@ -851,6 +879,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname) resolved_name = strdup(tmp_fname); if (!resolved_name) { DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname)); + errno = saved_errno; return False; } #else @@ -865,6 +894,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname) } default: DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname)); + errno = saved_errno; return False; } } @@ -875,13 +905,15 @@ BOOL reduce_name(connection_struct *conn, pstring fname) DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n")); if (free_resolved_name) SAFE_FREE(resolved_name); + errno = saved_errno; return False; } if (strncmp(conn->connectpath, resolved_name, con_path_len) != 0) { - DEBUG(2, ("reduce_name: Bad access attemt: %s is a symlink outside the share path", fname)); + DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname)); if (free_resolved_name) SAFE_FREE(resolved_name); + errno = EACCES; return False; } @@ -900,11 +932,13 @@ BOOL reduce_name(connection_struct *conn, pstring fname) DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",fname)); if (free_resolved_name) SAFE_FREE(resolved_name); + errno = EACCES; return False; } DEBUG(3,("reduce_name: %s reduced to %s\n", fname, p)); if (free_resolved_name) SAFE_FREE(resolved_name); + errno = saved_errno; return(True); } diff --git a/source/tdb/Makefile b/source/tdb/Makefile index 59fbb079bd0..92bc33a661e 100644 --- a/source/tdb/Makefile +++ b/source/tdb/Makefile @@ -5,11 +5,14 @@ CFLAGS = -DSTANDALONE -DTDB_DEBUG -g -DHAVE_MMAP=1 CC = gcc +ADMINPROGS = tdbdump tdbbackup PROGS = tdbtest tdbtool tdbtorture -TDB_OBJ = tdb.o spinlock.o +TDB_OBJ = tdb.o spinlock.o tdbback.o default: $(PROGS) +admintools: $(ADMINPROGS) + tdbtest: tdbtest.o $(TDB_OBJ) $(CC) $(CFLAGS) -o tdbtest tdbtest.o $(TDB_OBJ) -lgdbm diff --git a/source/torture/torture.c b/source/torture/torture.c index 161aa2cd73b..e3960d34061 100644 --- a/source/torture/torture.c +++ b/source/torture/torture.c @@ -45,12 +45,12 @@ static struct timeval tp1,tp2; void start_timer(void) { - gettimeofday(&tp1,NULL); + GetTimeOfDay(&tp1); } double end_timer(void) { - gettimeofday(&tp2,NULL); + GetTimeOfDay(&tp2); return((tp2.tv_sec - tp1.tv_sec) + (tp2.tv_usec - tp1.tv_usec)*1.0e-6); } diff --git a/source/torture/vfstest.c b/source/torture/vfstest.c index 88fe3486493..48556aa2570 100644 --- a/source/torture/vfstest.c +++ b/source/torture/vfstest.c @@ -466,7 +466,7 @@ BOOL reload_services(BOOL test) reset_stat_cache(); /* this forces service parameters to be flushed */ - set_current_service(NULL,True); + set_current_service(NULL,0,True); return (ret); } diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c index 6eec71aedf3..b25303a97e0 100644 --- a/source/utils/net_ads.c +++ b/source/utils/net_ads.c @@ -55,6 +55,8 @@ int net_ads_usage(int argc, const char **argv) "\n\tperform a raw LDAP search and dump the results\n" "\nnet ads dn"\ "\n\tperform a raw LDAP search and dump attributes of a particular DN\n" +"\nnet ads keytab"\ +"\n\tcreates and updates the kerberos system keytab file\n" ); return -1; } @@ -109,8 +111,8 @@ static int net_ads_info(int argc, const char **argv) d_printf("LDAP port: %d\n", ads->ldap_port); d_printf("Server time: %s\n", http_timestring(ads->config.current_time)); - d_printf("KDC server: %s\n", ads->auth.kdc_server ); - d_printf("Server time offset: %d\n", ads->auth.time_offset ); + d_printf("KDC server: %s\n", ads->auth.kdc_server ); + d_printf("Server time offset: %d\n", ads->auth.time_offset ); return 0; } @@ -214,6 +216,7 @@ static int net_ads_workgroup(int argc, const char **argv) if (!(ads = ads_startup())) return -1; if (!(ctx = talloc_init("net_ads_workgroup"))) { + ads_destroy(&ads); return -1; } @@ -221,13 +224,14 @@ static int net_ads_workgroup(int argc, const char **argv) d_printf("Failed to find workgroup for realm '%s'\n", ads->config.realm); talloc_destroy(ctx); + ads_destroy(&ads); return -1; } d_printf("Workgroup: %s\n", workgroup); talloc_destroy(ctx); - + ads_destroy(&ads); return 0; } @@ -274,7 +278,9 @@ static int ads_user_add(int argc, const char **argv) if (argc < 1) return net_ads_user_usage(argc, argv); - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } status = ads_find_user_acct(ads, &res, argv[0]); @@ -342,13 +348,18 @@ static int ads_user_info(int argc, const char **argv) char **grouplist; char *escaped_user = escape_ldap_string_alloc(argv[0]); - if (argc < 1) return net_ads_user_usage(argc, argv); + if (argc < 1) { + return net_ads_user_usage(argc, argv); + } - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } if (!escaped_user) { d_printf("ads_user_info: failed to escape user %s\n", argv[0]); - return -1; + ads_destroy(&ads); + return -1; } asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user); @@ -357,6 +368,7 @@ static int ads_user_info(int argc, const char **argv) if (!ADS_ERR_OK(rc)) { d_printf("ads_search: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } @@ -374,7 +386,6 @@ static int ads_user_info(int argc, const char **argv) } ads_msgfree(ads, res); - ads_destroy(&ads); return 0; } @@ -386,13 +397,18 @@ static int ads_user_delete(int argc, const char **argv) void *res; char *userdn; - if (argc < 1) return net_ads_user_usage(argc, argv); + if (argc < 1) { + return net_ads_user_usage(argc, argv); + } - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } rc = ads_find_user_acct(ads, &res, argv[0]); if (!ADS_ERR_OK(rc)) { DEBUG(0, ("User %s does not exist\n", argv[0])); + ads_destroy(&ads); return -1; } userdn = ads_get_dn(ads, res); @@ -401,10 +417,12 @@ static int ads_user_delete(int argc, const char **argv) ads_memfree(ads, userdn); if (!ADS_ERR_OK(rc)) { d_printf("User %s deleted\n", argv[0]); + ads_destroy(&ads); return 0; } d_printf("Error deleting user %s: %s\n", argv[0], ads_errstr(rc)); + ads_destroy(&ads); return -1; } @@ -423,7 +441,9 @@ int net_ads_user(int argc, const char **argv) char *disp_fields[2] = {NULL, NULL}; if (argc == 0) { - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } if (opt_long_list_entries) d_printf("\nUser name Comment"\ @@ -454,9 +474,13 @@ static int ads_group_add(int argc, const char **argv) void *res=NULL; int rc = -1; - if (argc < 1) return net_ads_group_usage(argc, argv); + if (argc < 1) { + return net_ads_group_usage(argc, argv); + } - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } status = ads_find_user_acct(ads, &res, argv[0]); @@ -495,13 +519,18 @@ static int ads_group_delete(int argc, const char **argv) void *res; char *groupdn; - if (argc < 1) return net_ads_group_usage(argc, argv); + if (argc < 1) { + return net_ads_group_usage(argc, argv); + } - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } rc = ads_find_user_acct(ads, &res, argv[0]); if (!ADS_ERR_OK(rc)) { DEBUG(0, ("Group %s does not exist\n", argv[0])); + ads_destroy(&ads); return -1; } groupdn = ads_get_dn(ads, res); @@ -510,10 +539,12 @@ static int ads_group_delete(int argc, const char **argv) ads_memfree(ads, groupdn); if (!ADS_ERR_OK(rc)) { d_printf("Group %s deleted\n", argv[0]); + ads_destroy(&ads); return 0; } d_printf("Error deleting group %s: %s\n", argv[0], ads_errstr(rc)); + ads_destroy(&ads); return -1; } @@ -531,7 +562,9 @@ int net_ads_group(int argc, const char **argv) char *disp_fields[2] = {NULL, NULL}; if (argc == 0) { - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } if (opt_long_list_entries) d_printf("\nGroup name Comment"\ @@ -555,21 +588,25 @@ static int net_ads_status(int argc, const char **argv) ADS_STATUS rc; void *res; - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } rc = ads_find_machine_acct(ads, &res, global_myname()); if (!ADS_ERR_OK(rc)) { d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } if (ads_count_replies(ads, res) == 0) { d_printf("No machine account for '%s' found\n", global_myname()); + ads_destroy(&ads); return -1; } ads_dump(ads, res); - + ads_destroy(&ads); return 0; } @@ -593,13 +630,14 @@ static int net_ads_leave(int argc, const char **argv) rc = ads_leave_realm(ads, global_myname()); if (!ADS_ERR_OK(rc)) { - d_printf("Failed to delete host '%s' from the '%s' realm.\n", - global_myname(), ads->config.realm); - return -1; + d_printf("Failed to delete host '%s' from the '%s' realm.\n", + global_myname(), ads->config.realm); + ads_destroy(&ads); + return -1; } d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm); - + ads_destroy(&ads); return 0; } @@ -659,7 +697,9 @@ int net_ads_join(int argc, const char **argv) const char *short_domain_name = NULL; TALLOC_CTX *ctx = NULL; - if (argc > 0) org_unit = argv[0]; + if (argc > 0) { + org_unit = argv[0]; + } if (!secrets_init()) { DEBUG(1,("Failed to initialise secrets database\n")); @@ -669,15 +709,19 @@ int net_ads_join(int argc, const char **argv) tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); password = strdup(tmp_password); - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } if (!*lp_realm()) { d_printf("realm must be set in in smb.conf for ADS join to succeed.\n"); + ads_destroy(&ads); return -1; } if (strcmp(ads->config.realm, lp_realm()) != 0) { d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm()); + ads_destroy(&ads); return -1; } @@ -691,35 +735,41 @@ int net_ads_join(int argc, const char **argv) if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) { d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", org_unit, dn); + ads_destroy(&ads); return -1; } free(dn); if (!ADS_ERR_OK(rc)) { d_printf("ads_join_realm: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } rc = ads_join_realm(ads, global_myname(), account_type, org_unit); if (!ADS_ERR_OK(rc)) { d_printf("ads_join_realm: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } rc = ads_domain_sid(ads, &dom_sid); if (!ADS_ERR_OK(rc)) { d_printf("ads_domain_sid: %s\n", ads_errstr(rc)); - return -1; + ads_destroy(&ads); + return -1; } if (asprintf(&machine_account, "%s$", global_myname()) == -1) { d_printf("asprintf failed\n"); + ads_destroy(&ads); return -1; } rc = ads_set_machine_password(ads, machine_account, password); if (!ADS_ERR_OK(rc)) { d_printf("ads_set_machine_password: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } @@ -727,6 +777,7 @@ int net_ads_join(int argc, const char **argv) if ( !(ctx = talloc_init("net ads join")) ) { d_printf("talloc_init() failed!\n"); + ads_destroy(&ads); return -1; } @@ -738,9 +789,9 @@ int net_ads_join(int argc, const char **argv) d_printf("Using the name [%s] from the server.\n", short_domain_name); d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name); } - } - else + } else { short_domain_name = lp_workgroup(); + } d_printf("Using short domain name -- %s\n", short_domain_name); @@ -751,30 +802,41 @@ int net_ads_join(int argc, const char **argv) if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) { DEBUG(1,("Failed to save domain sid\n")); + ads_destroy(&ads); return -1; } if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) { DEBUG(1,("Failed to save machine password\n")); + ads_destroy(&ads); return -1; } if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) { DEBUG(1,("Failed to save domain sid\n")); + ads_destroy(&ads); return -1; } if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) { DEBUG(1,("Failed to save machine password\n")); + ads_destroy(&ads); return -1; } + /* Now build the keytab, using the same ADS connection */ + if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) { + DEBUG(1,("Error creating host keytab!\n")); + } + d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm); SAFE_FREE(password); SAFE_FREE(machine_account); - if ( ctx ) + if ( ctx ) { talloc_destroy(ctx); + } + ads_destroy(&ads); return 0; } @@ -801,26 +863,29 @@ static int net_ads_printer_search(int argc, const char **argv) ADS_STATUS rc; void *res = NULL; - if (!(ads = ads_startup())) + if (!(ads = ads_startup())) { return -1; + } rc = ads_find_printers(ads, &res); if (!ADS_ERR_OK(rc)) { d_printf("ads_find_printer: %s\n", ads_errstr(rc)); ads_msgfree(ads, res); - return -1; + ads_destroy(&ads); + return -1; } if (ads_count_replies(ads, res) == 0) { d_printf("No results found\n"); ads_msgfree(ads, res); + ads_destroy(&ads); return -1; } ads_dump(ads, res); ads_msgfree(ads, res); - + ads_destroy(&ads); return 0; } @@ -831,34 +896,41 @@ static int net_ads_printer_info(int argc, const char **argv) const char *servername, *printername; void *res = NULL; - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } - if (argc > 0) + if (argc > 0) { printername = argv[0]; - else + } else { printername = "*"; + } - if (argc > 1) + if (argc > 1) { servername = argv[1]; - else + } else { servername = global_myname(); + } rc = ads_find_printer_on_server(ads, &res, printername, servername); if (!ADS_ERR_OK(rc)) { d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc)); ads_msgfree(ads, res); + ads_destroy(&ads); return -1; } if (ads_count_replies(ads, res) == 0) { d_printf("Printer '%s' not found\n", printername); ads_msgfree(ads, res); + ads_destroy(&ads); return -1; } ads_dump(ads, res); ads_msgfree(ads, res); + ads_destroy(&ads); return 0; } @@ -881,17 +953,21 @@ static int net_ads_printer_publish(int argc, const char **argv) char *prt_dn, *srv_dn, **srv_cn; void *res = NULL; - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } - if (argc < 1) + if (argc < 1) { return net_ads_printer_usage(argc, argv); + } printername = argv[0]; - if (argc == 2) + if (argc == 2) { servername = argv[1]; - else + } else { servername = global_myname(); + } /* Get printer data from SPOOLSS */ @@ -908,6 +984,7 @@ static int net_ads_printer_publish(int argc, const char **argv) if (NT_STATUS_IS_ERR(nt_status)) { d_printf("Unable to open a connnection to %s to obtain data " "for %s\n", servername, printername); + ads_destroy(&ads); return -1; } @@ -918,6 +995,7 @@ static int net_ads_printer_publish(int argc, const char **argv) if (ads_count_replies(ads, res) == 0) { d_printf("Could not find machine account for server %s\n", servername); + ads_destroy(&ads); return -1; } @@ -932,10 +1010,12 @@ static int net_ads_printer_publish(int argc, const char **argv) rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods); if (!ADS_ERR_OK(rc)) { d_printf("ads_publish_printer: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } d_printf("published printer\n"); + ads_destroy(&ads); return 0; } @@ -948,27 +1028,33 @@ static int net_ads_printer_remove(int argc, const char **argv) char *prt_dn; void *res = NULL; - if (!(ads = ads_startup())) return -1; + if (!(ads = ads_startup())) { + return -1; + } - if (argc < 1) + if (argc < 1) { return net_ads_printer_usage(argc, argv); + } - if (argc > 1) + if (argc > 1) { servername = argv[1]; - else + } else { servername = global_myname(); + } rc = ads_find_printer_on_server(ads, &res, argv[0], servername); if (!ADS_ERR_OK(rc)) { d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc)); ads_msgfree(ads, res); + ads_destroy(&ads); return -1; } if (ads_count_replies(ads, res) == 0) { d_printf("Printer '%s' not found\n", argv[1]); ads_msgfree(ads, res); + ads_destroy(&ads); return -1; } @@ -979,9 +1065,11 @@ static int net_ads_printer_remove(int argc, const char **argv) if (!ADS_ERR_OK(rc)) { d_printf("ads_del_dn: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } + ads_destroy(&ads); return 0; } @@ -1001,116 +1089,123 @@ static int net_ads_printer(int argc, const char **argv) static int net_ads_password(int argc, const char **argv) { - ADS_STRUCT *ads; - const char *auth_principal = opt_user_name; - const char *auth_password = opt_password; - char *realm = NULL; - char *new_password = NULL; - char *c, *prompt; - const char *user; - ADS_STATUS ret; - - if (opt_user_name == NULL || opt_password == NULL) { - d_printf("You must supply an administrator username/password\n"); - return -1; - } + ADS_STRUCT *ads; + const char *auth_principal = opt_user_name; + const char *auth_password = opt_password; + char *realm = NULL; + char *new_password = NULL; + char *c, *prompt; + const char *user; + ADS_STATUS ret; + + if (opt_user_name == NULL || opt_password == NULL) { + d_printf("You must supply an administrator username/password\n"); + return -1; + } + if (argc < 1) { + d_printf("ERROR: You must say which username to change password for\n"); + return -1; + } + + user = argv[0]; + if (!strchr_m(user, '@')) { + asprintf(&c, "%s@%s", argv[0], lp_realm()); + user = c; + } + + use_in_memory_ccache(); + c = strchr(auth_principal, '@'); + if (c) { + realm = ++c; + } else { + realm = lp_realm(); + } + + /* use the realm so we can eventually change passwords for users + in realms other than default */ + if (!(ads = ads_init(realm, NULL, NULL))) { + return -1; + } + + /* we don't actually need a full connect, but it's the easy way to + fill in the KDC's addresss */ + ads_connect(ads); - if (argc < 1) { - d_printf("ERROR: You must say which username to change password for\n"); - return -1; - } - - user = argv[0]; - if (!strchr(user, '@')) { - asprintf(&c, "%s@%s", argv[0], lp_realm()); - user = c; - } - - use_in_memory_ccache(); - c = strchr(auth_principal, '@'); - if (c) { - realm = ++c; - } else { - realm = lp_realm(); - } - - /* use the realm so we can eventually change passwords for users - in realms other than default */ - if (!(ads = ads_init(realm, NULL, NULL))) return -1; - - /* we don't actually need a full connect, but it's the easy way to - fill in the KDC's addresss */ - ads_connect(ads); - - if (!ads || !ads->config.realm) { - d_printf("Didn't find the kerberos server!\n"); - return -1; - } - - if (argv[1]) { - new_password = (char *)argv[1]; - } else { - asprintf(&prompt, "Enter new password for %s:", user); - new_password = getpass(prompt); - free(prompt); - } - - ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, + if (!ads || !ads->config.realm) { + d_printf("Didn't find the kerberos server!\n"); + return -1; + } + + if (argv[1]) { + new_password = (char *)argv[1]; + } else { + asprintf(&prompt, "Enter new password for %s:", user); + new_password = getpass(prompt); + free(prompt); + } + + ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, auth_password, user, new_password, ads->auth.time_offset); - if (!ADS_ERR_OK(ret)) { - d_printf("Password change failed :-( ...\n"); - ads_destroy(&ads); - return -1; - } + if (!ADS_ERR_OK(ret)) { + d_printf("Password change failed :-( ...\n"); + ads_destroy(&ads); + return -1; + } - d_printf("Password change for %s completed.\n", user); - ads_destroy(&ads); + d_printf("Password change for %s completed.\n", user); + ads_destroy(&ads); - return 0; + return 0; } - int net_ads_changetrustpw(int argc, const char **argv) { - ADS_STRUCT *ads; - char *host_principal; - char *hostname; - ADS_STATUS ret; + ADS_STRUCT *ads; + char *host_principal; + fstring my_fqdn; + ADS_STATUS ret; + + if (!secrets_init()) { + DEBUG(1,("Failed to initialise secrets database\n")); + return -1; + } + + net_use_machine_password(); - if (!secrets_init()) { - DEBUG(1,("Failed to initialise secrets database\n")); - return -1; - } + use_in_memory_ccache(); - net_use_machine_password(); + if (!(ads = ads_startup())) { + return -1; + } - use_in_memory_ccache(); + name_to_fqdn(my_fqdn, global_myname()); + strlower_m(my_fqdn); + asprintf(&host_principal, "%s@%s", my_fqdn, ads->config.realm); + d_printf("Changing password for principal: HOST/%s\n", host_principal); - if (!(ads = ads_startup())) { - return -1; - } + ret = ads_change_trust_account_password(ads, host_principal); - hostname = strdup(global_myname()); - strlower_m(hostname); - asprintf(&host_principal, "%s@%s", hostname, ads->config.realm); - SAFE_FREE(hostname); - d_printf("Changing password for principal: HOST/%s\n", host_principal); + if (!ADS_ERR_OK(ret)) { + d_printf("Password change failed :-( ...\n"); + ads_destroy(&ads); + SAFE_FREE(host_principal); + return -1; + } - ret = ads_change_trust_account_password(ads, host_principal); + d_printf("Password change for principal HOST/%s succeeded.\n", host_principal); + + if (lp_use_kerberos_keytab()) { + d_printf("Attempting to update system keytab with new password.\n"); + if (ads_keytab_create_default(ads)) { + d_printf("Failed to update system keytab.\n"); + } + } - if (!ADS_ERR_OK(ret)) { - d_printf("Password change failed :-( ...\n"); ads_destroy(&ads); SAFE_FREE(host_principal); - return -1; - } - - d_printf("Password change for principal HOST/%s succeeded.\n", host_principal); - ads_destroy(&ads); - SAFE_FREE(host_principal); - return 0; + return 0; } /* @@ -1157,6 +1252,7 @@ static int net_ads_search(int argc, const char **argv) ldap_exp, attrs, &res); if (!ADS_ERR_OK(rc)) { d_printf("search failed: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } @@ -1216,6 +1312,7 @@ static int net_ads_dn(int argc, const char **argv) "(objectclass=*)", attrs, &res); if (!ADS_ERR_OK(rc)) { d_printf("search failed: %s\n", ads_errstr(rc)); + ads_destroy(&ads); return -1; } @@ -1230,6 +1327,86 @@ static int net_ads_dn(int argc, const char **argv) return 0; } +static int net_ads_keytab_usage(int argc, const char **argv) +{ + d_printf( + "net ads keytab \n"\ +" can be either:\n"\ +" CREATE Creates a fresh keytab\n"\ +" ADD Adds new service principal\n"\ +" FLUSH Flushes out all keytab entries\n"\ +" HELP Prints this help message\n"\ +"The ADD command will take arguments, the other commands\n"\ +"will not take any arguments. The arguments given to ADD\n"\ +"should be a list of principals to add. For example, \n"\ +" net ads keytab add srv1 srv2\n"\ +"will add principals for the services srv1 and srv2 to the\n"\ +"system's keytab.\n"\ +"\n" + ); + return -1; +} + +static int net_ads_keytab_flush(int argc, const char **argv) +{ + int ret; + ADS_STRUCT *ads; + + if (!(ads = ads_startup())) { + return -1; + } + ret = ads_keytab_flush(ads); + ads_destroy(&ads); + return ret; +} + +static int net_ads_keytab_add(int argc, const char **argv) +{ + int i; + int ret = 0; + ADS_STRUCT *ads; + + d_printf("Processing principals to add...\n"); + if (!(ads = ads_startup())) { + return -1; + } + for (i = 0; i < argc; i++) { + ret |= ads_keytab_add_entry(ads, argv[i]); + } + ads_destroy(&ads); + return ret; +} + +static int net_ads_keytab_create(int argc, const char **argv) +{ + ADS_STRUCT *ads; + int ret; + + if (!(ads = ads_startup())) { + return -1; + } + ret = ads_keytab_create_default(ads); + ads_destroy(&ads); + return ret; +} + +int net_ads_keytab(int argc, const char **argv) +{ + struct functable func[] = { + {"CREATE", net_ads_keytab_create}, + {"ADD", net_ads_keytab_add}, + {"FLUSH", net_ads_keytab_flush}, + {"HELP", net_ads_keytab_usage}, + {NULL, NULL} + }; + + if (!lp_use_kerberos_keytab()) { + d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \ +use keytab functions.\n"); + } + + return net_run_function(argc, argv, func, net_ads_keytab_usage); +} int net_ads_help(int argc, const char **argv) { @@ -1269,6 +1446,7 @@ int net_ads(int argc, const char **argv) {"DN", net_ads_dn}, {"WORKGROUP", net_ads_workgroup}, {"LOOKUP", net_ads_lookup}, + {"KEYTAB", net_ads_keytab}, {"HELP", net_ads_help}, {NULL, NULL} }; @@ -1284,6 +1462,11 @@ static int net_ads_noads(void) return -1; } +int net_ads_keytab(int argc, const char **argv) +{ + return net_ads_noads(); +} + int net_ads_usage(int argc, const char **argv) { return net_ads_noads(); diff --git a/source/utils/net_rpc.c b/source/utils/net_rpc.c index 817ba912b05..e21f79df303 100644 --- a/source/utils/net_rpc.c +++ b/source/utils/net_rpc.c @@ -1867,8 +1867,14 @@ rpc_group_list_internals(const DOM_SID *domain_sid, const char *domain_name, do { if (!local) break; + /* The max_size field in cli_samr_enum_als_groups is more like + * an account_control field with indiviual bits what to + * retrieve. Set this to 0xffff as NT4 usrmgr.exe does to get + * everything. I'm too lazy (sorry) to get this through to + * rpc_parse/ etc. Volker */ + result = cli_samr_enum_als_groups(cli, mem_ctx, &domain_pol, - &start_idx, max_entries, + &start_idx, 0xffff, &groups, &num_entries); if (!NT_STATUS_IS_OK(result) && @@ -2203,6 +2209,83 @@ static int rpc_group_members(int argc, const char **argv) argc, argv); } +static NTSTATUS +rpc_group_rename_internals(const DOM_SID *domain_sid, + const char *domain_name, + struct cli_state *cli, + TALLOC_CTX *mem_ctx, int argc, const char **argv) +{ + NTSTATUS result; + POLICY_HND connect_pol, domain_pol, group_pol; + uint32 num_rids, *rids, *rid_types; + GROUP_INFO_CTR ctr; + + if (argc != 2) { + d_printf("Usage: 'net rpc group rename group newname'\n"); + return NT_STATUS_UNSUCCESSFUL; + } + + /* Get sam policy handle */ + + result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + return result; + + /* Get domain policy handle */ + + result = cli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + domain_sid, &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + return result; + + result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol, 1000, + 1, argv, &num_rids, &rids, &rid_types); + + if (num_rids != 1) { + d_printf("Couldn't find group %s\n", argv[0]); + return result; + } + + if (rid_types[0] != SID_NAME_DOM_GRP) { + d_printf("Can only rename domain groups\n"); + return NT_STATUS_UNSUCCESSFUL; + } + + result = cli_samr_open_group(cli, mem_ctx, &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + rids[0], &group_pol); + + if (!NT_STATUS_IS_OK(result)) + return result; + + ZERO_STRUCT(ctr); + + ctr.switch_value1 = 2; + init_samr_group_info2(&ctr.group.info2, argv[1]); + + result = cli_samr_set_groupinfo(cli, mem_ctx, &group_pol, &ctr); + + if (!NT_STATUS_IS_OK(result)) + return result; + + return NT_STATUS_NO_SUCH_GROUP; +} + +static int rpc_group_rename(int argc, const char **argv) +{ + if (argc != 2) { + return rpc_group_usage(argc, argv); + } + + return run_rpc_command(NULL, PI_SAMR, 0, + rpc_group_rename_internals, + argc, argv); +} + /** * 'net rpc group' entrypoint. * @param argc Standard main() style argc @@ -2219,6 +2302,7 @@ int net_rpc_group(int argc, const char **argv) {"delmem", rpc_group_delmem}, {"list", rpc_group_list}, {"members", rpc_group_members}, + {"rename", rpc_group_rename}, {NULL, NULL} }; diff --git a/source/utils/ntlm_auth.c b/source/utils/ntlm_auth.c index f2fb7dcaaf3..39dcd9993d0 100644 --- a/source/utils/ntlm_auth.c +++ b/source/utils/ntlm_auth.c @@ -369,6 +369,7 @@ NTSTATUS contact_winbind_auth_crap(const char *username, nt_status = NT_STATUS_UNSUCCESSFUL; if (error_string) *error_string = smb_xstrdup("Reading winbind reply failed!"); + free_response(&response); return nt_status; } @@ -376,6 +377,7 @@ NTSTATUS contact_winbind_auth_crap(const char *username, if (!NT_STATUS_IS_OK(nt_status)) { if (error_string) *error_string = smb_xstrdup(response.data.auth.error_string); + free_response(&response); return nt_status; } @@ -390,10 +392,12 @@ NTSTATUS contact_winbind_auth_crap(const char *username, if (flags & WBFLAG_PAM_UNIX_NAME) { if (pull_utf8_allocate(unix_name, (char *)response.extra_data) == -1) { + free_response(&response); return NT_STATUS_NO_MEMORY; } } + free_response(&response); return nt_status; } @@ -810,32 +814,34 @@ static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode, pstring reply_argument; if (strlen(buf) < 2) { + DEBUG(1, ("SPENGO query [%s] invalid", buf)); + x_fprintf(x_stdout, "BH\n"); + return; + } - if (ntlmssp_state != NULL) { - DEBUG(1, ("Request for initial SPNEGO request where " - "we already have a state\n")); - x_fprintf(x_stdout, "BH\n"); - return; - } - - DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); + if (strncmp(buf, "YR", 2) == 0) { + if (ntlmssp_state) + ntlmssp_end(&ntlmssp_state); + } else if (strncmp(buf, "KK", 2) == 0) { + + } else { + DEBUG(1, ("SPENGO query [%s] invalid", buf)); x_fprintf(x_stdout, "BH\n"); return; } - if ( (strlen(buf) == 2) && (strcmp(buf, "YR") == 0) ) { + if ( (strlen(buf) == 2)) { - /* Initial request, get the negTokenInit offering + /* no client data, get the negTokenInit offering mechanisms */ offer_gss_spnego_mechs(); return; } - /* All subsequent requests are "KK" (Knock, Knock ;)) and have - a blob. This might be negTokenInit or negTokenTarg */ + /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */ - if ( (strlen(buf) <= 3) || (strncmp(buf, "KK", 2) != 0) ) { + if (strlen(buf) <= 3) { DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH\n"); return; @@ -1147,7 +1153,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) { char *principal; DATA_BLOB tkt, to_server; - DATA_BLOB session_key_krb5; + DATA_BLOB session_key_krb5 = data_blob(NULL, 0); SPNEGO_DATA reply; char *reply_base64; int retval; @@ -1192,14 +1198,14 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) { DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval))); - x_fprintf(x_stdout, "NA\n"); - return True; + return False; } retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5); if (retval) { DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval))); + return False; } } @@ -1588,9 +1594,13 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helpe /* this is not a typo - x_fgets doesn't work too well under squid */ if (fgets(buf, sizeof(buf)-1, stdin) == NULL) { - DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin), - strerror(ferror(stdin)))); - exit(1); /* BIIG buffer */ + if (ferror(stdin)) { + DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin), + strerror(ferror(stdin)))); + + exit(1); /* BIIG buffer */ + } + exit(0); } c=memchr(buf,'\n',sizeof(buf)-1); diff --git a/source/utils/smbcacls.c b/source/utils/smbcacls.c index 5a70d168842..cb82ad831eb 100644 --- a/source/utils/smbcacls.c +++ b/source/utils/smbcacls.c @@ -624,11 +624,6 @@ static int cacl_set(struct cli_state *cli, char *filename, old->dacl->ace[k] = old->dacl->ace[k+1]; } old->dacl->num_aces--; - if (old->dacl->num_aces == 0) { - SAFE_FREE(old->dacl->ace); - SAFE_FREE(old->dacl); - old->off_dacl = 0; - } found = True; break; } -- 2.11.4.GIT