diff options
Diffstat (limited to 'source')
84 files changed, 5897 insertions, 2499 deletions
diff --git a/source/Makefile.in b/source/Makefile.in index 5d3462913c1..b6fe22b5934 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -35,8 +35,6 @@ IDMAP_LIBS=@IDMAP_LIBS@ KRB5LIBS=@KRB5_LIBS@ LDAP_LIBS=@LDAP_LIBS@ -LINK=$(CC) $(FLAGS) $(LDFLAGS) - INSTALLCMD=@INSTALL@ INSTALLCLIENTCMD_SH=@INSTALLCLIENTCMD_SH@ INSTALLCLIENTCMD_A=@INSTALLCLIENTCMD_A@ @@ -199,7 +197,7 @@ LIB_OBJ = $(VERSION_OBJ) lib/charcnv.o lib/debug.o lib/fault.o \ lib/util_str.o lib/clobber.o lib/util_sid.o lib/util_uuid.o \ lib/util_unistr.o lib/util_file.o lib/data_blob.o \ lib/util.o lib/util_sock.o lib/sock_exec.o lib/util_sec.o \ - lib/talloc.o lib/hash.o lib/substitute.o lib/fsusage.o \ + lib/talloc.o lib/substitute.o lib/fsusage.o \ lib/ms_fnmatch.o lib/select.o lib/messages.o \ lib/tallocmsg.o lib/dmallocmsg.o libsmb/smb_signing.o \ lib/md5.o lib/hmacmd5.o lib/iconv.o \ @@ -397,7 +395,7 @@ SMBD_OBJ_BASE = $(PARAM_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \ $(LIBMSRPC_OBJ) \ $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(LIBADS_SERVER_OBJ) \ $(LIB_SMBD_OBJ) $(REGISTRY_OBJ) $(POPT_LIB_OBJ) \ - $(UBIQX_OBJ) $(BUILDOPT_OBJ) $(SMBLDAP_OBJ) + $(BUILDOPT_OBJ) $(SMBLDAP_OBJ) PRINTING_OBJ = printing/pcap.o printing/print_svid.o \ printing/print_cups.o printing/print_generic.o \ @@ -533,7 +531,7 @@ NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_ads_cldap.o utils/net_help.o \ utils/net_rap.o utils/net_rpc.o utils/net_rpc_samsync.o \ utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \ utils/net_cache.o utils/net_groupmap.o utils/net_idmap.o \ - utils/net_status.o + utils/net_status.o utils/net_rpc_printer.o NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \ $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ @@ -847,27 +845,27 @@ bin/net@EXEEXT@: $(NET_OBJ) @BUILD_POPT@ bin/.dummy bin/profiles@EXEEXT@: $(PROFILES_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(PROFILES_OBJ) $(LDFLAGS) $(LIBS) @POPTLIBS@ + @$(CC) $(FLAGS) -o $@ $(PROFILES_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@ bin/editreg@EXEEXT@: $(EDITREG_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(EDITREG_OBJ) $(LDFLAGS) $(LIBS) @POPTLIBS@ + @$(CC) $(FLAGS) -o $@ $(EDITREG_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) @POPTLIBS@ bin/smbspool@EXEEXT@: $(CUPS_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(CUPS_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(CUPS_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) bin/smbmount@EXEEXT@: $(MOUNT_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(MOUNT_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(MOUNT_OBJ) $(DYNEXP) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) bin/smbmnt@EXEEXT@: $(MNT_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(MNT_OBJ) $(LDFLAGS) + @$(CC) $(FLAGS) -o $@ $(MNT_OBJ) $(DYNEXP) $(LDFLAGS) bin/smbumount@EXEEXT@: $(UMOUNT_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(UMOUNT_OBJ) $(LDFLAGS) + @$(CC) $(FLAGS) -o $@ $(UMOUNT_OBJ) $(DYNEXP) $(LDFLAGS) bin/testparm@EXEEXT@: $(TESTPARM_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @@ -919,15 +917,15 @@ bin/smbtorture@EXEEXT@: $(SMBTORTURE_OBJ) bin/.dummy bin/talloctort@EXEEXT@: $(TALLOCTORT_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(TALLOCTORT_OBJ) $(LDFLAGS) $(LIBS) + @$(CC) $(FLAGS) -o $@ $(TALLOCTORT_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) bin/masktest@EXEEXT@: $(MASKTEST_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(MASKTEST_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(SECRETS_OBJ) + @$(CC) $(FLAGS) -o $@ $(MASKTEST_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(SECRETS_OBJ) bin/msgtest@EXEEXT@: $(MSGTEST_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(MSGTEST_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(MSGTEST_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) bin/smbcacls@EXEEXT@: $(SMBCACLS_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @@ -939,11 +937,11 @@ bin/smbcquotas@EXEEXT@: $(SMBCQUOTAS_OBJ) @BUILD_POPT@ bin/.dummy bin/locktest@EXEEXT@: $(LOCKTEST_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(LOCKTEST_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(LOCKTEST_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) bin/nsstest@EXEEXT@: $(NSSTEST_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(NSSTEST_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(NSSTEST_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) bin/vfstest@EXEEXT@: $(VFSTEST_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @@ -955,11 +953,11 @@ bin/smbiconv@EXEEXT@: $(SMBICONV_OBJ) @BUILD_POPT@ bin/.dummy bin/log2pcap@EXEEXT@: $(LOG2PCAP_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(LOG2PCAP_OBJ) $(LDFLAGS) @POPTLIBS@ $(LIBS) + @$(CC) $(FLAGS) -o $@ $(LOG2PCAP_OBJ) $(LDFLAGS) $(DYNEXP) @POPTLIBS@ $(LIBS) bin/locktest2@EXEEXT@: $(LOCKTEST2_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(LOCKTEST2_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(LOCKTEST2_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) bin/rpctorture@EXEEXT@: $(RPCTORTURE_OBJ) bin/.dummy @echo Linking $@ @@ -967,15 +965,15 @@ bin/rpctorture@EXEEXT@: $(RPCTORTURE_OBJ) bin/.dummy bin/debug2html@EXEEXT@: $(DEBUG2HTML_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(DEBUG2HTML_OBJ) $(LDFLAGS) $(LIBS) + @$(CC) $(FLAGS) -o $@ $(DEBUG2HTML_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) bin/smbfilter@EXEEXT@: $(SMBFILTER_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(SMBFILTER_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(SMBFILTER_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) bin/smbw_sample@EXEEXT@: $(SMBW_OBJ) utils/smbw_sample.o bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(SMBW_OBJ) utils/smbw_sample.o $(LDFLAGS) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(SMBW_OBJ) utils/smbw_sample.o $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) bin/smbsh@EXEEXT@: $(SMBSH_OBJ) bin/.dummy @echo Linking $@ @@ -989,7 +987,7 @@ bin/smbwrapper.@SHLIBEXT@: $(PICOBJS) bin/.dummy bin/libsmbclient.@SHLIBEXT@: $(LIBSMBCLIENT_PICOBJS) @echo Linking libsmbclient shared library $@ - @$(SHLD) $(LDSHFLAGS) -o $@ $(LIBSMBCLIENT_PICOBJS) $(LDFLAGS) $(DYNEXP) $(LIBS) \ + @$(SHLD) $(LDSHFLAGS) -o $@ $(LIBSMBCLIENT_PICOBJS) $(LDFLAGS) $(LIBS) \ $(KRB5LIBS) $(LDAP_LIBS) \ @SONAMEFLAG@`basename $@`.$(LIBSMBCLIENT_MAJOR) @@ -1064,7 +1062,8 @@ bin/librpc_echo.@SHLIBEXT@: $(RPC_ECHO_OBJ) bin/winbindd@EXEEXT@: $(WINBINDD_OBJ) @BUILD_POPT@ bin/.dummy @echo "Linking $@" - @$(LINK) -o $@ $(WINBINDD_OBJ) $(DYNEXP) $(LIBS) @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) $(PASSDB_LIBS) + @$(CC) $(FLAGS) -o $@ $(WINBINDD_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \ + @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) $(PASSDB_LIBS) # Please don't add .o files to libnss_winbind, libnss_wins, or the pam_winbind # libraries. Add to the appropriate PICOBJ variable instead. @@ -1225,13 +1224,14 @@ bin/afsacl.@SHLIBEXT@: $(VFS_AFSACL_OBJ:.o=.po) bin/wbinfo@EXEEXT@: $(WBINFO_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ - @$(LINK) -o $@ $(WBINFO_OBJ) $(LIBS) @POPTLIBS@ + @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(WBINFO_OBJ) $(DYNEXP) $(LIBS) @POPTLIBS@ bin/ntlm_auth@EXEEXT@: $(NTLM_AUTH_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ $(UBIQX_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ - @$(LINK) -o $@ $(NTLM_AUTH_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ - $(UBIQX_OBJ) $(LIBS) @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) + @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(DYNEXP) $(NTLM_AUTH_OBJ) \ + $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(UBIQX_OBJ) $(LIBS) \ + @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) bin/pam_smbpass.@SHLIBEXT@: $(PAM_SMBPASS_PICOOBJ) @echo "Linking shared library $@" @@ -1242,28 +1242,28 @@ bin/libmsrpc.a: $(LIBMSRPC_PICOBJ) bin/tdbbackup@EXEEXT@: $(TDBBACKUP_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(TDBBACKUP_OBJ) + @$(CC) $(FLAGS) -o $@ $(DYNEXP) $(TDBBACKUP_OBJ) bin/tdbdump@EXEEXT@: $(TDBDUMP_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(TDBDUMP_OBJ) + @$(CC) $(FLAGS) -o $@ $(DYNEXP) $(TDBDUMP_OBJ) bin/t_strcmp@EXEEXT@: bin/libbigballofmud.@SHLIBEXT@ torture/t_strcmp.o - $(CC) $(FLAGS) -o $@ $(LIBS) torture/t_strcmp.o -L ./bin -lbigballofmud + $(CC) $(FLAGS) -o $@ $(DYNEXP) $(LIBS) torture/t_strcmp.o -L ./bin -lbigballofmud bin/t_strstr@EXEEXT@: bin/libbigballofmud.@SHLIBEXT@ torture/t_strstr.o - $(CC) $(FLAGS) -o $@ $(LIBS) torture/t_strstr.o -L ./bin -lbigballofmud + $(CC) $(FLAGS) -o $@ $(DYNEXP) $(LIBS) torture/t_strstr.o -L ./bin -lbigballofmud bin/t_stringoverflow@EXEEXT@: bin/libbigballofmud.@SHLIBEXT@ torture/t_stringoverflow.o - $(CC) $(FLAGS) -o $@ torture/t_stringoverflow.o -L./bin -lbigballofmud + $(CC) $(FLAGS) -o $@ $(DYNEXP) torture/t_stringoverflow.o -L./bin -lbigballofmud bin/t_doschar@EXEEXT@: bin/libbigballofmud.@SHLIBEXT@ torture/t_doschar.o - $(CC) $(FLAGS) -o $@ $(LIBS) torture/t_doschar.o -L ./bin -lbigballofmud + $(CC) $(FLAGS) -o $@ $(DYNEXP) $(LIBS) torture/t_doschar.o -L ./bin -lbigballofmud bin/t_push_ucs2@EXEEXT@: bin/libbigballofmud.@SHLIBEXT@ torture/t_push_ucs2.o - $(CC) $(FLAGS) -o $@ $(LIBS) torture/t_push_ucs2.o -L ./bin -lbigballofmud + $(CC) $(FLAGS) -o $@ $(DYNEXP) $(LIBS) torture/t_push_ucs2.o -L ./bin -lbigballofmud bin/t_snprintf@EXEEXT@: lib/snprintf.c - $(CC) $(FLAGS) -o $@ -DTEST_SNPRINTF lib/snprintf.c -lm + $(CC) $(FLAGS) -o $@ $(DYNEXP) -DTEST_SNPRINTF lib/snprintf.c -lm install: installbin installman installscripts installdat installswat installmodules @INSTALLCLIENT@ install-everything: install installmodules diff --git a/source/VERSION b/source/VERSION index ab14d54bdd0..f33e71fb577 100644 --- a/source/VERSION +++ b/source/VERSION @@ -19,7 +19,7 @@ ######################################################## SAMBA_VERSION_MAJOR=3 SAMBA_VERSION_MINOR=0 -SAMBA_VERSION_RELEASE=7 +SAMBA_VERSION_RELEASE=8 ######################################################## # For 'pre' releases the version will be # @@ -29,7 +29,7 @@ SAMBA_VERSION_RELEASE=7 # e.g. SAMBA_VERSION_PRE_RELEASE=1 # # -> "2.2.9pre1" # ######################################################## -SAMBA_VERSION_PRE_RELEASE= +SAMBA_VERSION_PRE_RELEASE=1 ######################################################## # For 'rc' releases the version will be # diff --git a/source/client/client.c b/source/client/client.c index 1fccfaa581c..e14bcaa2616 100644 --- a/source/client/client.c +++ b/source/client/client.c @@ -592,7 +592,7 @@ static int cmd_dir(void) else pstrcat(mask,p); } else { - pstrcat(mask,"*"); + pstrcat(mask,"\\*"); } do_list(mask, attribute, display_finfo, recurse, True); diff --git a/source/client/clitar.c b/source/client/clitar.c index 64c194b54da..4cadef558d6 100644 --- a/source/client/clitar.c +++ b/source/client/clitar.c @@ -1345,8 +1345,9 @@ Principal command for creating / extracting int cmd_tar(void) { fstring buf; - char **argl; - int argcl; + char **argl = NULL; + int argcl = 0; + int ret; if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { DEBUG(0,("tar <c|x>[IXbgan] <filename>\n")); @@ -1357,8 +1358,9 @@ int cmd_tar(void) if (!tar_parseargs(argcl, argl, buf, 0)) return 1; + ret = process_tar(); SAFE_FREE(argl); - return process_tar(); + return ret; } /**************************************************************************** diff --git a/source/configure.in b/source/configure.in index 53267f0cd95..69152d8fc8f 100644 --- a/source/configure.in +++ b/source/configure.in @@ -414,7 +414,6 @@ case "$host_os" in AC_DEFINE(_MAX_ALIGNMENT, 4, [Maximum alignment]) ;; esac - DYNEXP="-Wl,-E" ;; # @@ -1215,9 +1214,9 @@ if test "$enable_shared" = "yes"; then # Use special PIC flags for the native HP-UX compiler. if test $ac_cv_prog_cc_Ae = yes; then BLDSHARED="true" - SHLD="/usr/bin/ld" - LDSHFLAGS="-B symbolic -b -z" - SONAMEFLAG="+h " + SHLD="cc" + LDSHFLAGS="-b -Wl,-B,symbolic,-b,-z" + SONAMEFLAG="-Wl,+h " PICFLAGS="+z" elif test "${GCC}" = "yes"; then PICFLAGS="-fPIC" @@ -1302,13 +1301,14 @@ fi if test $BLDSHARED = true; then AC_CACHE_CHECK([whether building shared libraries actually works], [ac_cv_shlib_works],[ - ac_cv_shlib_works=no # try building a trivial shared library + ac_cv_shlib_works=no + # The $SHLD and $LDSHFLAGS variables may contain references to other + # variables so they need to be eval'ed. $CC $CPPFLAGS $CFLAGS $PICFLAGS -c -o \ shlib.$PICSUFFIX ${srcdir-.}/tests/shlib.c && \ - $CC $CPPFLAGS $CFLAGS `eval echo $LDSHFLAGS` -o "shlib.$SHLIBEXT" \ - shlib.$PICSUFFIX && \ - ac_cv_shlib_works=yes + `eval echo $SHLD` `eval echo $LDSHFLAGS` -o "shlib.$SHLIBEXT" \ + shlib.$PICSUFFIX && ac_cv_shlib_works=yes rm -f "shlib.$SHLIBEXT" shlib.$PICSUFFIX ]) if test $ac_cv_shlib_works = no; then @@ -2761,6 +2761,7 @@ if test x"$with_ads_support" != x"no"; then 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) + AC_CHECK_FUNC_EXT(krb5_krbhst_get_addrinfo, $KRB5_LIBS) LIBS="$LIBS $KRB5_LIBS" @@ -4235,7 +4236,7 @@ AC_SUBST(WINBIND_NSS_LDSHFLAGS) AC_SUBST(WINBIND_NSS_EXTRA_OBJS) AC_SUBST(WINBIND_NSS_EXTRA_LIBS) -# Check the setting of --with-winbindd +# Check the setting of --with-winbind AC_ARG_WITH(winbind, [ --with-winbind Build winbind (default, if supported by OS)], diff --git a/source/include/charset.h b/source/include/charset.h index 7a9b12ef55d..c5d03a62e89 100644 --- a/source/include/charset.h +++ b/source/include/charset.h @@ -31,9 +31,9 @@ typedef enum {CH_UCS2=0, CH_UNIX=1, CH_DISPLAY=2, CH_DOS=3, CH_UTF8=4} charset_t struct charset_functions { const char *name; - size_t (*pull)(void *, char **inbuf, size_t *inbytesleft, + size_t (*pull)(void *, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); - size_t (*push)(void *, char **inbuf, size_t *inbytesleft, + size_t (*push)(void *, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); struct charset_functions *prev, *next; }; @@ -57,7 +57,7 @@ struct charset_gap_table { * * */ #define SMB_GENERATE_CHARSET_MODULE_8_BIT_GAP(CHARSETNAME) \ -static size_t CHARSETNAME ## _push(void *cd, char **inbuf, size_t *inbytesleft, \ +static size_t CHARSETNAME ## _push(void *cd, const char **inbuf, size_t *inbytesleft, \ char **outbuf, size_t *outbytesleft) \ { \ while (*inbytesleft >= 2 && *outbytesleft >= 1) { \ @@ -97,7 +97,7 @@ static size_t CHARSETNAME ## _push(void *cd, char **inbuf, size_t *inbytesleft, return 0; \ } \ \ -static size_t CHARSETNAME ## _pull(void *cd, char **inbuf, size_t *inbytesleft, \ +static size_t CHARSETNAME ## _pull(void *cd, const char **inbuf, size_t *inbytesleft, \ char **outbuf, size_t *outbytesleft) \ { \ while (*inbytesleft >= 1 && *outbytesleft >= 2) { \ @@ -124,4 +124,3 @@ NTSTATUS charset_ ## CHARSETNAME ## _init(void) \ return smb_register_charset(& CHARSETNAME ## _functions); \ } \ - diff --git a/source/include/fake_file.h b/source/include/fake_file.h index cfcd16f6830..63ba41d7860 100644 --- a/source/include/fake_file.h +++ b/source/include/fake_file.h @@ -28,9 +28,9 @@ enum FAKE_FILE_TYPE { /* we now get the unix name --metze -#define FAKE_FILE_NAME_QUOTA "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION" */ -#define FAKE_FILE_NAME_QUOTA "$Extend/$Quota:$Q:$INDEX_ALLOCATION" +#define FAKE_FILE_NAME_QUOTA_WIN32 "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION" +#define FAKE_FILE_NAME_QUOTA_UNIX "$Extend/$Quota:$Q:$INDEX_ALLOCATION" typedef struct _FAKE_FILE_HANDLE { enum FAKE_FILE_TYPE type; diff --git a/source/include/hash.h b/source/include/hash.h deleted file mode 100644 index 40cc8b7cab3..00000000000 --- a/source/include/hash.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Copyright (C) Ying Chen 2000. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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. -*/ - -#ifndef _HASH_H_ -#define _HASH_H_ - -#define MAX_HASH_TABLE_SIZE 16384 -#define HASH_TABLE_INCREMENT 2 - -typedef int (*compare_function)(char *, char *); -typedef int (*hash_function)(int, char *); - -/* - * lru_link: links the node to the LRU list. - * hash_elem: the pointer to the element that is tied onto the link. - */ -typedef struct lru_node { - ubi_dlNode lru_link; - void *hash_elem; -} lru_node; - -/* - * bucket_link: link the hash element to the bucket chain that it belongs to. - * lru_link: this element ties the hash element to the lru list. - * bucket: a pointer to the hash bucket that this element belongs to. - * value: a pointer to the hash element content. It can be anything. - * key: stores the string key. The hash_element is always allocated with - * more memory space than the structure shown below to accomodate the space - * used for the whole string. But the memory is always appended at the - * end of the structure, so keep "key" at the end of the structure. - * Don't move it. - */ -typedef struct hash_element { - ubi_dlNode bucket_link; - lru_node lru_link; - ubi_dlList *bucket; - void *value; - char key[1]; -} hash_element; - -/* - * buckets: a list of buckets, implemented as a dLinkList. - * lru_chain: the lru list of all the hash elements. - * num_elements: the # of elements in the hash table. - * size: the hash table size. - * comp_func: the compare function used during hash key comparisons. - */ - -typedef struct hash_table { - ubi_dlList *buckets; - ubi_dlList lru_chain; - unsigned num_elements; - unsigned size; - compare_function comp_func; -} hash_table; - -#endif /* _HASH_H_ */ diff --git a/source/include/includes.h b/source/include/includes.h index 1d913d3f32a..3ea4eaa35a9 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -45,10 +45,11 @@ #undef HAVE_TERMIOS_H #endif -#ifdef __GNUC__ +#if (__GNUC__ >= 3) /** Use gcc attribute to check printf fns. a1 is the 1-based index of * the parameter containing the format, and a2 the index of the first - * argument. **/ + * argument. Note that some gcc 2.x versions don't handle this + * properly **/ #define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) #else #define PRINTF_ATTRIBUTE(a1, a2) @@ -309,6 +310,19 @@ #endif #ifdef HAVE_SHADOW_H +/* + * HP-UX 11.X has TCP_NODELAY and TCP_MAXSEG defined in <netinet/tcp.h> which + * was included above. However <rpc/rpc.h> includes <sys/xti.h> which defines + * them again without checking if they already exsist. This generates + * two "Redefinition of macro" warnings for every single .c file that is + * compiled. + */ +#if defined(HPUX) && defined(TCP_NODELAY) +#undef TCP_NODELAY +#endif +#if defined(HPUX) && defined(TCP_MAXSEG) +#undef TCP_MAXSEG +#endif #include <shadow.h> #endif @@ -361,6 +375,19 @@ #if defined(HAVE_SYS_SECURITY_H) && defined(HAVE_RPC_AUTH_ERROR_CONFLICT) #undef AUTH_ERROR #endif +/* + * HP-UX 11.X has TCP_NODELAY and TCP_MAXSEG defined in <netinet/tcp.h> which + * was included above. However <rpc/rpc.h> includes <sys/xti.h> which defines + * them again without checking if they already exsist. This generates + * two "Redefinition of macro" warnings for every single .c file that is + * compiled. + */ +#if defined(HPUX) && defined(TCP_NODELAY) +#undef TCP_NODELAY +#endif +#if defined(HPUX) && defined(TCP_MAXSEG) +#undef TCP_MAXSEG +#endif #include <rpc/rpc.h> #endif @@ -369,12 +396,25 @@ #endif #if defined (HAVE_NETGROUP) -#if defined(HAVE_RPCSVC_YPCLNT_H) -#include <rpcsvc/ypclnt.h> -#endif #if defined(HAVE_RPCSVC_YP_PROT_H) +/* + * HP-UX 11.X has TCP_NODELAY and TCP_MAXSEG defined in <netinet/tcp.h> which + * was included above. However <rpc/rpc.h> includes <sys/xti.h> which defines + * them again without checking if they already exsist. This generates + * two "Redefinition of macro" warnings for every single .c file that is + * compiled. + */ +#if defined(HPUX) && defined(TCP_NODELAY) +#undef TCP_NODELAY +#endif +#if defined(HPUX) && defined(TCP_MAXSEG) +#undef TCP_MAXSEG +#endif #include <rpcsvc/yp_prot.h> #endif +#if defined(HAVE_RPCSVC_YPCLNT_H) +#include <rpcsvc/ypclnt.h> +#endif #endif /* HAVE_NETGROUP */ #if defined(HAVE_SYS_IPC_H) @@ -760,7 +800,6 @@ extern int errno; #include "nt_status.h" #include "ads.h" #include "interfaces.h" -#include "hash.h" #include "trans2.h" #include "nterr.h" #include "ntioctl.h" diff --git a/source/include/rpc_spoolss.h b/source/include/rpc_spoolss.h index cf7d1ba3412..f2b78f91bc0 100755 --- a/source/include/rpc_spoolss.h +++ b/source/include/rpc_spoolss.h @@ -1026,6 +1026,7 @@ typedef struct printer_info_ctr_info PRINTER_INFO_3 *printers_3; PRINTER_INFO_4 *printers_4; PRINTER_INFO_5 *printers_5; + PRINTER_INFO_7 *printers_7; } PRINTER_INFO_CTR; diff --git a/source/include/smb.h b/source/include/smb.h index 32dba0cf78f..7317fd16b0f 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -1658,11 +1658,11 @@ struct unix_error_map { /* generic iconv conversion structure */ typedef struct { - size_t (*direct)(void *cd, char **inbuf, size_t *inbytesleft, + size_t (*direct)(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); - size_t (*pull)(void *cd, char **inbuf, size_t *inbytesleft, + size_t (*pull)(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); - size_t (*push)(void *cd, char **inbuf, size_t *inbytesleft, + size_t (*push)(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); void *cd_direct, *cd_pull, *cd_push; char *from_name, *to_name; diff --git a/source/include/smb_macros.h b/source/include/smb_macros.h index bcbaa64f863..a9e911c066a 100644 --- a/source/include/smb_macros.h +++ b/source/include/smb_macros.h @@ -26,7 +26,6 @@ /* Misc bit macros */ #define BOOLSTR(b) ((b) ? "Yes" : "No") -#define BITSETB(ptr,bit) ((((char *)ptr)[0] & (1<<(bit)))!=0) #define BITSETW(ptr,bit) ((SVAL(ptr,0) & (1<<(bit)))!=0) /* for readability... */ diff --git a/source/include/smbldap.h b/source/include/smbldap.h index 953937fb75d..58502ec34e7 100644 --- a/source/include/smbldap.h +++ b/source/include/smbldap.h @@ -107,7 +107,9 @@ typedef struct _attrib_map_entry { /* structures */ extern ATTRIB_MAP_ENTRY attrib_map_v22[]; +extern ATTRIB_MAP_ENTRY attrib_map_to_delete_v22[]; extern ATTRIB_MAP_ENTRY attrib_map_v30[]; +extern ATTRIB_MAP_ENTRY attrib_map_to_delete_v30[]; extern ATTRIB_MAP_ENTRY dominfo_attr_list[]; extern ATTRIB_MAP_ENTRY groupmap_attr_list[]; extern ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[]; diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c index 6cbf7562b06..40004826b4a 100644 --- a/source/lib/charcnv.c +++ b/source/lib/charcnv.c @@ -56,7 +56,7 @@ static const char *charset_name(charset_t ch) { const char *ret = NULL; - if (ch == CH_UCS2) ret = "UCS-2LE"; + if (ch == CH_UCS2) ret = "UTF-16LE"; else if (ch == CH_UNIX) ret = lp_unix_charset(); else if (ch == CH_DOS) ret = lp_dos_charset(); else if (ch == CH_DISPLAY) ret = lp_display_charset(); @@ -116,10 +116,10 @@ void init_iconv(void) /* so that charset_name() works we need to get the UNIX<->UCS2 going first */ if (!conv_handles[CH_UNIX][CH_UCS2]) - conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open("UCS-2LE", "ASCII"); + conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open(charset_name(CH_UCS2), "ASCII"); if (!conv_handles[CH_UCS2][CH_UNIX]) - conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", "UCS-2LE"); + conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", charset_name(CH_UCS2)); for (c1=0;c1<NUM_CHARSETS;c1++) { for (c2=0;c2<NUM_CHARSETS;c2++) { @@ -216,7 +216,7 @@ static size_t convert_string_internal(charset_t from, charset_t to, again: - retval = smb_iconv(descriptor, (char **)&inbuf, &i_len, &outbuf, &o_len); + retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len); if(retval==(size_t)-1) { const char *reason="unknown error"; switch(errno) { @@ -229,14 +229,18 @@ static size_t convert_string_internal(charset_t from, charset_t to, break; case E2BIG: reason="No more room"; - if (!conv_silent) - DEBUG(3, ("convert_string_internal: Required %lu, available %lu\n", - (unsigned long)srclen, (unsigned long)destlen)); - /* we are not sure we need srclen bytes, - may be more, may be less. - We only know we need more than destlen - bytes ---simo */ - break; + if (!conv_silent) { + if (from == CH_UNIX) { + DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u - '%s'\n", + charset_name(from), charset_name(to), + (unsigned int)srclen, (unsigned int)destlen, (const char *)src)); + } else { + DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u\n", + charset_name(from), charset_name(to), + (unsigned int)srclen, (unsigned int)destlen)); + } + } + break; case EILSEQ: reason="Illegal multibyte sequence"; if (!conv_silent) @@ -531,7 +535,7 @@ size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to, again: retval = smb_iconv(descriptor, - (char **)&inbuf, &i_len, + &inbuf, &i_len, &outbuf, &o_len); if(retval == (size_t)-1) { const char *reason="unknown error"; diff --git a/source/lib/hash.c b/source/lib/hash.c deleted file mode 100644 index 18b6534dec2..00000000000 --- a/source/lib/hash.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Copyright (C) Ying Chen 2000. - Copyright (C) Jeremy Allison 2000. - - added some defensive programming. - - 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. -*/ - -/* - * NB. We may end up replacing this functionality in a future 2.x - * release to reduce the number of hashing/lookup methods we support. JRA. - */ - -#include "includes.h" - -static BOOL enlarge_hash_table(hash_table *table); -static unsigned primes[] = - {17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 16411}; - -/**************************************************************************** - * This function initializes the hash table. - * This hash function hashes on string keys. - * This number of hash buckets is always rounded up to a power of - * 2 first, then to a prime number that is large than the power of two. - * Input: - * table -- the hash table pointer. - * num_buckets -- the number of buckets to be allocated. This - * hash function can dynamically increase its size when the - * the hash table size becomes small. There is a MAX hash table - * size defined in hash.h. - * compare_func -- the function pointer to a comparison function - * used by the hash key comparison. - **************************************************************************** - */ - -BOOL hash_table_init(hash_table *table, unsigned num_buckets, compare_function compare_func) -{ - unsigned i; - ubi_dlList *bucket; - - table->num_elements = 0; - table->size = 2; - table->comp_func = compare_func; - while (table->size < num_buckets) - table->size <<= 1; - for (i = 0; i < ARRAY_SIZE(primes); i++) { - if (primes[i] > table->size) { - table->size = primes[i]; - break; - } - } - - DEBUG(5, ("Hash size = %d.\n", table->size)); - - if(!(table->buckets = (ubi_dlList *) malloc(sizeof(ubi_dlList) * table->size))) { - DEBUG(0,("hash_table_init: malloc fail !\n")); - return False; - } - ubi_dlInitList(&(table->lru_chain)); - for (i=0, bucket = table->buckets; i < table->size; i++, bucket++) - ubi_dlInitList(bucket); - - return True; -} - -/* - ************************************************************** - * Compute a hash value based on a string key value. - * Make the string key into an array of int's if possible. - * For the last few chars that cannot be int'ed, use char instead. - * The function returns the bucket index number for the hashed - * key. - * JRA. Use a djb-algorithm hash for speed. - ************************************************************** - */ - -static int string_hash(int hash_size, const char *key) -{ - u32 n = 0; - const char *p; - for (p = key; *p != '\0'; p++) { - n = ((n << 5) + n) ^ (u32)(*p); - } - return (n % hash_size); -} - -/* ************************************************************************* - * Search the hash table for the entry in the hash chain. - * The function returns the pointer to the - * element found in the chain or NULL if none is found. - * If the element is found, the element is also moved to - * the head of the LRU list. - * - * Input: - * table -- The hash table where the element is stored in. - * hash_chain -- The pointer to the bucket that stores the - * element to be found. - * key -- The hash key to be found. - *************************************************************************** - */ - -static hash_element *hash_chain_find(hash_table *table, ubi_dlList *hash_chain, char *key) -{ - hash_element *hash_elem; - ubi_dlNodePtr lru_item; - unsigned int i = 0; - - for (hash_elem = (hash_element *)(ubi_dlFirst(hash_chain)); i < hash_chain->count; - i++, hash_elem = (hash_element *)(ubi_dlNext(hash_elem))) { - if ((table->comp_func)(hash_elem->key, key) == 0) { - /* Move to the head of the lru List. */ - lru_item = ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); - ubi_dlAddHead(&(table->lru_chain), lru_item); - return(hash_elem); - } - } - return ((hash_element *) NULL); -} - -/* *************************************************************************** - * - * Lookup a hash table for an element with key. - * The function returns a pointer to the hash element. - * If no element is found, the function returns NULL. - * - * Input: - * table -- The hash table to be searched on. - * key -- The key to be found. - ***************************************************************************** - */ - -hash_element *hash_lookup(hash_table *table, char *key) -{ - return (hash_chain_find(table, &table->buckets[string_hash(table->size, key)], key)); -} - -/* *************************************************************** - * - * This function first checks if an element with key "key" - * exists in the hash table. If so, the function moves the - * element to the front of the LRU list. Otherwise, a new - * hash element corresponding to "value" and "key" is allocated - * and inserted into the hash table. The new elements are - * always inserted in the LRU order to the LRU list as well. - * - * Input: - * table -- The hash table to be inserted in. - * value -- The content of the element to be inserted. - * key -- The key of the new element to be inserted. - * - **************************************************************** - */ - -hash_element *hash_insert(hash_table *table, char *value, char *key) -{ - hash_element *hash_elem; - ubi_dlNodePtr lru_item; - ubi_dlList *bucket; - size_t string_length; - - /* - * If the hash table size has not reached the MAX_HASH_TABLE_SIZE, - * the hash table may be enlarged if the current hash table is full. - * If the hash table size has reached the MAX_HASH_TABLE_SIZE, - * use LRU to remove the oldest element from the hash table. - */ - - if ((table->num_elements >= table->size) && - (table->num_elements < MAX_HASH_TABLE_SIZE)) { - if(!enlarge_hash_table(table)) - return (hash_element *)NULL; - table->num_elements += 1; - } else if (table->num_elements >= MAX_HASH_TABLE_SIZE) { - /* Do an LRU replacement. */ - lru_item = ubi_dlLast(&(table->lru_chain)); - hash_elem = (hash_element *)(((lru_node *)lru_item)->hash_elem); - bucket = hash_elem->bucket; - ubi_dlRemThis(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); - ubi_dlRemThis(bucket, (ubi_dlNodePtr)hash_elem); - SAFE_FREE(hash_elem->value); - SAFE_FREE(hash_elem); - } else { - table->num_elements += 1; - } - - bucket = &table->buckets[string_hash(table->size, key)]; - - /* Since we only have 1-byte for the key string, we need to - * allocate extra space in the hash_element to store the entire key - * string. - */ - - string_length = strlen(key); - if(!(hash_elem = (hash_element *) malloc(sizeof(hash_element) + string_length))) { - DEBUG(0,("hash_insert: malloc fail !\n")); - return (hash_element *)NULL; - } - - safe_strcpy((char *) hash_elem->key, key, string_length); - - hash_elem->value = (char *)value; - hash_elem->bucket = bucket; - /* Insert in front of the lru list and the bucket list. */ - ubi_dlAddHead(bucket, hash_elem); - hash_elem->lru_link.hash_elem = hash_elem; - ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); - - return(hash_elem); -} - -/* ************************************************************************** - * - * Remove a hash element from the hash table. The hash element is - * removed from both the LRU list and the hash bucket chain. - * - * Input: - * table -- the hash table to be manipulated on. - * hash_elem -- the element to be removed. - ************************************************************************** - */ - -void hash_remove(hash_table *table, hash_element *hash_elem) -{ - if (hash_elem) { - ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); - ubi_dlRemove(hash_elem->bucket, (ubi_dlNodePtr) hash_elem); - SAFE_FREE(hash_elem->value); - SAFE_FREE(hash_elem); - table->num_elements--; - } -} - -/* ****************************************************************** - * Increase the hash table size if it is too small. - * The hash table size is increased by the HASH_TABLE_INCREMENT - * ratio. - * Input: - * table -- the hash table to be enlarged. - ****************************************************************** - */ - -static BOOL enlarge_hash_table(hash_table *table) -{ - hash_element *hash_elem; - int size, hash_value; - ubi_dlList *buckets; - ubi_dlList *old_bucket; - ubi_dlList *bucket; - ubi_dlList lru_chain; - - buckets = table->buckets; - lru_chain = table->lru_chain; - size = table->size; - - /* Reinitialize the hash table. */ - if(!hash_table_init(table, table->size * HASH_TABLE_INCREMENT, table->comp_func)) - return False; - - for (old_bucket = buckets; size > 0; size--, old_bucket++) { - while (old_bucket->count != 0) { - hash_elem = (hash_element *) ubi_dlRemHead(old_bucket); - ubi_dlRemove(&lru_chain, &(hash_elem->lru_link.lru_link)); - hash_value = string_hash(table->size, (char *) hash_elem->key); - bucket = &(table->buckets[hash_value]); - ubi_dlAddHead(bucket, hash_elem); - ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); - hash_elem->bucket = bucket; - hash_elem->lru_link.hash_elem = hash_elem; - table->num_elements++; - } - } - SAFE_FREE(buckets); - - return True; -} - -/* ********************************************************************** - * - * Remove everything from a hash table and free up the memory it - * occupies. - * Input: - * table -- the hash table to be cleared. - * - ************************************************************************* - */ - -void hash_clear(hash_table *table) -{ - unsigned int i; - ubi_dlList *bucket = table->buckets; - hash_element *hash_elem; - for (i = 0; i < table->size; bucket++, i++) { - while (bucket->count != 0) { - hash_elem = (hash_element *) ubi_dlRemHead(bucket); - SAFE_FREE(hash_elem->value); - SAFE_FREE(hash_elem); - } - } - table->size = 0; - SAFE_FREE(table->buckets); - table->buckets = NULL; -} diff --git a/source/lib/iconv.c b/source/lib/iconv.c index 4c9ecf992e6..66a6e6cd8bc 100644 --- a/source/lib/iconv.c +++ b/source/lib/iconv.c @@ -51,18 +51,26 @@ * @sa Samba Developers Guide **/ -static size_t ascii_pull(void *,char **, size_t *, char **, size_t *); -static size_t ascii_push(void *,char **, size_t *, char **, size_t *); -static size_t latin1_push(void *,char **, size_t *, char **, size_t *); -static size_t utf8_pull(void *,char **, size_t *, char **, size_t *); -static size_t utf8_push(void *,char **, size_t *, char **, size_t *); -static size_t ucs2hex_pull(void *,char **, size_t *, char **, size_t *); -static size_t ucs2hex_push(void *,char **, size_t *, char **, size_t *); -static size_t iconv_copy(void *,char **, size_t *, char **, size_t *); +static size_t ascii_pull(void *,const char **, size_t *, char **, size_t *); +static size_t ascii_push(void *,const char **, size_t *, char **, size_t *); +static size_t latin1_push(void *,const char **, size_t *, char **, size_t *); +static size_t utf8_pull(void *,const char **, size_t *, char **, size_t *); +static size_t utf8_push(void *,const char **, size_t *, char **, size_t *); +static size_t ucs2hex_pull(void *,const char **, size_t *, char **, size_t *); +static size_t ucs2hex_push(void *,const char **, size_t *, char **, size_t *); +static size_t iconv_copy(void *,const char **, size_t *, char **, size_t *); +static size_t iconv_swab (void *,const char **, size_t *, char **, size_t *); static struct charset_functions builtin_functions[] = { + /* windows is really neither UCS-2 not UTF-16 */ {"UCS-2LE", iconv_copy, iconv_copy}, + {"UTF-16LE", iconv_copy, iconv_copy}, + {"UCS-2BE", iconv_swab, iconv_swab}, + {"UTF-16BE", iconv_swab, iconv_swab}, + + /* we include the UTF-8 alias to cope with differing locale settings */ {"UTF8", utf8_pull, utf8_push}, + {"UTF-8", utf8_pull, utf8_push}, {"ASCII", ascii_pull, ascii_push}, {"646", ascii_pull, ascii_push}, {"ISO-8859-1", ascii_pull, latin1_push}, @@ -122,12 +130,12 @@ static void lazy_initialize_iconv(void) this ensures that we don't have a shift state remaining for character sets like SJIS */ static size_t sys_iconv(void *cd, - char **inbuf, size_t *inbytesleft, + const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { #ifdef HAVE_NATIVE_ICONV size_t ret = iconv((iconv_t)cd, - inbuf, inbytesleft, + (char **)inbuf, inbytesleft, outbuf, outbytesleft); if (ret == (size_t)-1) { int saved_errno = errno; @@ -148,7 +156,7 @@ static size_t sys_iconv(void *cd, * enough that Samba works on systems that don't have iconv. **/ size_t smb_iconv(smb_iconv_t cd, - char **inbuf, size_t *inbytesleft, + const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { char cvtbuf[2048]; @@ -158,7 +166,7 @@ size_t smb_iconv(smb_iconv_t cd, /* in many cases we can go direct */ if (cd->direct) { return cd->direct(cd->cd_direct, - (char **)inbuf, inbytesleft, outbuf, outbytesleft); + inbuf, inbytesleft, outbuf, outbytesleft); } @@ -168,20 +176,27 @@ size_t smb_iconv(smb_iconv_t cd, bufsize = sizeof(cvtbuf); if (cd->pull(cd->cd_pull, - (char **)inbuf, inbytesleft, &bufp, &bufsize) == -1 + inbuf, inbytesleft, &bufp, &bufsize) == -1 && errno != E2BIG) return -1; bufp = cvtbuf; bufsize = sizeof(cvtbuf) - bufsize; if (cd->push(cd->cd_push, - &bufp, &bufsize, + (const char **)&bufp, &bufsize, outbuf, outbytesleft) == -1) return -1; } return 0; } + +static BOOL is_utf16(const char *name) +{ + return strcasecmp(name, "UCS-2LE") == 0 || + strcasecmp(name, "UTF-16LE") == 0; +} + /* simple iconv_open() wrapper */ @@ -220,13 +235,17 @@ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode) /* check if we can use iconv for this conversion */ #ifdef HAVE_NATIVE_ICONV if (!ret->pull) { - ret->cd_pull = iconv_open("UCS-2LE", fromcode); + ret->cd_pull = iconv_open("UTF-16LE", fromcode); + if (ret->cd_pull == (iconv_t)-1) + ret->cd_pull = iconv_open("UCS-2LE", fromcode); if (ret->cd_pull != (iconv_t)-1) ret->pull = sys_iconv; } if (!ret->push) { - ret->cd_push = iconv_open(tocode, "UCS-2LE"); + ret->cd_push = iconv_open(tocode, "UTF-16LE"); + if (ret->cd_push == (iconv_t)-1) + ret->cd_push = iconv_open(tocode, "UCS-2LE"); if (ret->cd_push != (iconv_t)-1) ret->push = sys_iconv; } @@ -256,13 +275,13 @@ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode) } /* check for conversion to/from ucs2 */ - if (strcasecmp(fromcode, "UCS-2LE") == 0 && to) { + if (is_utf16(fromcode) && to) { ret->direct = to->push; ret->push = ret->pull = NULL; return ret; } - if (strcasecmp(tocode, "UCS-2LE") == 0 && from) { + if (is_utf16(tocode) && from) { ret->direct = from->pull; ret->push = ret->pull = NULL; return ret; @@ -270,13 +289,13 @@ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode) /* Check if we can do the conversion direct */ #ifdef HAVE_NATIVE_ICONV - if (strcasecmp(fromcode, "UCS-2LE") == 0) { + if (is_utf16(fromcode)) { ret->direct = sys_iconv; ret->cd_direct = ret->cd_push; ret->cd_push = NULL; return ret; } - if (strcasecmp(tocode, "UCS-2LE") == 0) { + if (is_utf16(tocode)) { ret->direct = sys_iconv; ret->cd_direct = ret->cd_pull; ret->cd_pull = NULL; @@ -313,7 +332,7 @@ int smb_iconv_close (smb_iconv_t cd) multi-byte character set support for english users ***********************************************************************/ -static size_t ascii_pull(void *cd, char **inbuf, size_t *inbytesleft, +static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { while (*inbytesleft >= 1 && *outbytesleft >= 2) { @@ -333,7 +352,7 @@ static size_t ascii_pull(void *cd, char **inbuf, size_t *inbytesleft, return 0; } -static size_t ascii_push(void *cd, char **inbuf, size_t *inbytesleft, +static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { int ir_count=0; @@ -360,7 +379,7 @@ static size_t ascii_push(void *cd, char **inbuf, size_t *inbytesleft, return ir_count; } -static size_t latin1_push(void *cd, char **inbuf, size_t *inbytesleft, +static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { int ir_count=0; @@ -387,7 +406,7 @@ static size_t latin1_push(void *cd, char **inbuf, size_t *inbytesleft, return ir_count; } -static size_t ucs2hex_pull(void *cd, char **inbuf, size_t *inbytesleft, +static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { while (*inbytesleft >= 1 && *outbytesleft >= 2) { @@ -430,7 +449,7 @@ static size_t ucs2hex_pull(void *cd, char **inbuf, size_t *inbytesleft, return 0; } -static size_t ucs2hex_push(void *cd, char **inbuf, size_t *inbytesleft, +static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { while (*inbytesleft >= 2 && *outbytesleft >= 1) { @@ -471,8 +490,32 @@ static size_t ucs2hex_push(void *cd, char **inbuf, size_t *inbytesleft, return 0; } +static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft) +{ + int n; + + n = MIN(*inbytesleft, *outbytesleft); + + swab(*inbuf, *outbuf, (n&~1)); + if (n&1) { + (*outbuf)[n-1] = 0; + } + + (*inbytesleft) -= n; + (*outbytesleft) -= n; + (*inbuf) += n; + (*outbuf) += n; + + if (*inbytesleft > 0) { + errno = E2BIG; + return -1; + } -static size_t iconv_copy(void *cd, char **inbuf, size_t *inbytesleft, + return 0; +} + +static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { int n; @@ -494,102 +537,234 @@ static size_t iconv_copy(void *cd, char **inbuf, size_t *inbytesleft, return 0; } -static size_t utf8_pull(void *cd, char **inbuf, size_t *inbytesleft, +static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { - while (*inbytesleft >= 1 && *outbytesleft >= 2) { - unsigned char *c = (unsigned char *)*inbuf; - unsigned char *uc = (unsigned char *)*outbuf; - int len = 1; + size_t in_left=*inbytesleft, out_left=*outbytesleft; + const uint8 *c = (const uint8 *)*inbuf; + uint8 *uc = (uint8 *)*outbuf; + while (in_left >= 1 && out_left >= 2) { if ((c[0] & 0x80) == 0) { uc[0] = c[0]; uc[1] = 0; - } else if ((c[0] & 0xf0) == 0xe0) { - if (*inbytesleft < 3) { - DEBUG(0,("short utf8 char\n")); - goto badseq; + c += 1; + in_left -= 1; + out_left -= 2; + uc += 2; + continue; + } + + if ((c[0] & 0xe0) == 0xc0) { + if (in_left < 2 || + (c[1] & 0xc0) != 0x80) { + errno = EILSEQ; + goto error; + } + uc[1] = (c[0]>>2) & 0x7; + uc[0] = (c[0]<<6) | (c[1]&0x3f); + c += 2; + in_left -= 2; + out_left -= 2; + uc += 2; + continue; + } + + if ((c[0] & 0xf0) == 0xe0) { + if (in_left < 3 || + (c[1] & 0xc0) != 0x80 || + (c[2] & 0xc0) != 0x80) { + errno = EILSEQ; + goto error; } uc[1] = ((c[0]&0xF)<<4) | ((c[1]>>2)&0xF); uc[0] = (c[1]<<6) | (c[2]&0x3f); - len = 3; - } else if ((c[0] & 0xe0) == 0xc0) { - if (*inbytesleft < 2) { - DEBUG(0,("short utf8 char\n")); - goto badseq; + c += 3; + in_left -= 3; + out_left -= 2; + uc += 2; + continue; + } + + if ((c[0] & 0xf8) == 0xf0) { + unsigned int codepoint; + if (in_left < 4 || + (c[1] & 0xc0) != 0x80 || + (c[2] & 0xc0) != 0x80 || + (c[3] & 0xc0) != 0x80) { + errno = EILSEQ; + goto error; } - uc[1] = (c[0]>>2) & 0x7; - uc[0] = (c[0]<<6) | (c[1]&0x3f); - len = 2; + codepoint = + (c[3]&0x3f) | + ((c[2]&0x3f)<<6) | + ((c[1]&0x3f)<<12) | + ((c[0]&0x7)<<18); + if (codepoint < 0x10000) { + /* accept UTF-8 characters that are not + minimally packed, but pack the result */ + uc[0] = (codepoint & 0xFF); + uc[1] = (codepoint >> 8); + c += 4; + in_left -= 4; + out_left -= 2; + uc += 2; + continue; + } + + codepoint -= 0x10000; + + if (out_left < 4) { + errno = E2BIG; + goto error; + } + + uc[0] = (codepoint>>10) & 0xFF; + uc[1] = (codepoint>>18) | 0xd8; + uc[2] = codepoint & 0xFF; + uc[3] = ((codepoint>>8) & 0x3) | 0xdc; + c += 4; + in_left -= 4; + out_left -= 4; + uc += 4; + continue; } - (*inbuf) += len; - (*inbytesleft) -= len; - (*outbytesleft) -= 2; - (*outbuf) += 2; + /* we don't handle 5 byte sequences */ + errno = EINVAL; + goto error; } - if (*inbytesleft > 0) { + if (in_left > 0) { errno = E2BIG; - return -1; + goto error; } - + + *inbytesleft = in_left; + *outbytesleft = out_left; + *inbuf = c; + *outbuf = uc; return 0; -badseq: - errno = EINVAL; +error: + *inbytesleft = in_left; + *outbytesleft = out_left; + *inbuf = c; + *outbuf = uc; return -1; } -static size_t utf8_push(void *cd, char **inbuf, size_t *inbytesleft, - char **outbuf, size_t *outbytesleft) +static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft) { - while (*inbytesleft >= 2 && *outbytesleft >= 1) { - unsigned char *c = (unsigned char *)*outbuf; - unsigned char *uc = (unsigned char *)*inbuf; - int len=1; - - if (uc[1] & 0xf8) { - if (*outbytesleft < 3) { - DEBUG(0,("short utf8 write\n")); - goto toobig; + size_t in_left=*inbytesleft, out_left=*outbytesleft; + uint8 *c = (uint8 *)*outbuf; + const uint8 *uc = (const uint8 *)*inbuf; + + while (in_left >= 2 && out_left >= 1) { + unsigned int codepoint; + + if (uc[1] == 0 && !(uc[0] & 0x80)) { + /* simplest case */ + c[0] = uc[0]; + in_left -= 2; + out_left -= 1; + uc += 2; + c += 1; + continue; + } + + if ((uc[1]&0xf8) == 0) { + /* next simplest case */ + if (out_left < 2) { + errno = E2BIG; + goto error; } - c[0] = 0xe0 | (uc[1]>>4); - c[1] = 0x80 | ((uc[1]&0xF)<<2) | (uc[0]>>6); - c[2] = 0x80 | (uc[0]&0x3f); - len = 3; - } else if (uc[1] | (uc[0] & 0x80)) { - if (*outbytesleft < 2) { - DEBUG(0,("short utf8 write\n")); - goto toobig; + c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2); + c[1] = 0x80 | (uc[0] & 0x3f); + in_left -= 2; + out_left -= 2; + uc += 2; + c += 2; + continue; + } + + if ((uc[1] & 0xfc) == 0xdc) { + /* its the second part of a 4 byte sequence. Illegal */ + if (in_left < 4) { + errno = EINVAL; + } else { + errno = EILSEQ; } - c[0] = 0xc0 | (uc[1]<<2) | (uc[0]>>6); - c[1] = 0x80 | (uc[0]&0x3f); - len = 2; - } else { - c[0] = uc[0]; + goto error; } + if ((uc[1] & 0xfc) != 0xd8) { + codepoint = uc[0] | (uc[1]<<8); + if (out_left < 3) { + errno = E2BIG; + goto error; + } + c[0] = 0xe0 | (codepoint >> 12); + c[1] = 0x80 | ((codepoint >> 6) & 0x3f); + c[2] = 0x80 | (codepoint & 0x3f); + + in_left -= 2; + out_left -= 3; + uc += 2; + c += 3; + continue; + } - (*inbytesleft) -= 2; - (*outbytesleft) -= len; - (*inbuf) += 2; - (*outbuf) += len; + /* its the first part of a 4 byte sequence */ + if (in_left < 4) { + errno = EINVAL; + goto error; + } + if ((uc[3] & 0xfc) != 0xdc) { + errno = EILSEQ; + goto error; + } + codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) | + (uc[0]<<10) | ((uc[1] & 0x3)<<18)); + + if (out_left < 4) { + errno = E2BIG; + goto error; + } + c[0] = 0xf0 | (codepoint >> 18); + c[1] = 0x80 | ((codepoint >> 12) & 0x3f); + c[2] = 0x80 | ((codepoint >> 6) & 0x3f); + c[3] = 0x80 | (codepoint & 0x3f); + + in_left -= 4; + out_left -= 4; + uc += 4; + c += 4; } - if (*inbytesleft == 1) { + if (in_left == 1) { errno = EINVAL; - return -1; + goto error; } - if (*inbytesleft > 1) { + if (in_left > 1) { errno = E2BIG; - return -1; + goto error; } + + *inbytesleft = in_left; + *outbytesleft = out_left; + *inbuf = uc; + *outbuf = c; return 0; -toobig: - errno = E2BIG; +error: + *inbytesleft = in_left; + *outbytesleft = out_left; + *inbuf = uc; + *outbuf = c; return -1; } + diff --git a/source/lib/ms_fnmatch.c b/source/lib/ms_fnmatch.c index 24232c3b523..42c91bd18df 100644 --- a/source/lib/ms_fnmatch.c +++ b/source/lib/ms_fnmatch.c @@ -179,6 +179,9 @@ static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string, break; case UCS2_CHAR('*'): + while (*p == UCS2_CHAR('*')) { + p++; + } for (; *n; n++) { if (ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0; } diff --git a/source/lib/smbldap.c b/source/lib/smbldap.c index e66fb3640cf..57aab70a5ba 100644 --- a/source/lib/smbldap.c +++ b/source/lib/smbldap.c @@ -66,6 +66,29 @@ ATTRIB_MAP_ENTRY attrib_map_v22[] = { { LDAP_ATTR_DOMAIN, "domain" }, { LDAP_ATTR_OBJCLASS, "objectClass" }, { LDAP_ATTR_ACB_INFO, "acctFlags" }, + { LDAP_ATTR_MOD_TIMESTAMP, "modifyTimestamp" }, + { LDAP_ATTR_LIST_END, NULL } +}; + +ATTRIB_MAP_ENTRY attrib_map_to_delete_v22[] = { + { LDAP_ATTR_PWD_LAST_SET, "pwdLastSet" }, + { LDAP_ATTR_PWD_CAN_CHANGE, "pwdCanChange" }, + { LDAP_ATTR_PWD_MUST_CHANGE, "pwdMustChange" }, + { LDAP_ATTR_LOGON_TIME, "logonTime" }, + { LDAP_ATTR_LOGOFF_TIME, "logoffTime" }, + { LDAP_ATTR_KICKOFF_TIME, "kickoffTime" }, + { LDAP_ATTR_DISPLAY_NAME, "displayName" }, + { LDAP_ATTR_HOME_PATH, "smbHome" }, + { LDAP_ATTR_HOME_DRIVE, "homeDrives" }, + { LDAP_ATTR_LOGON_SCRIPT, "scriptPath" }, + { LDAP_ATTR_PROFILE_PATH, "profilePath" }, + { LDAP_ATTR_USER_WKS, "userWorkstations"}, + { LDAP_ATTR_USER_RID, "rid" }, + { LDAP_ATTR_PRIMARY_GROUP_RID, "primaryGroupID"}, + { LDAP_ATTR_LMPW, "lmPassword" }, + { LDAP_ATTR_NTPW, "ntPassword" }, + { LDAP_ATTR_DOMAIN, "domain" }, + { LDAP_ATTR_ACB_INFO, "acctFlags" }, { LDAP_ATTR_LIST_END, NULL } }; @@ -106,6 +129,32 @@ ATTRIB_MAP_ENTRY attrib_map_v30[] = { { LDAP_ATTR_LIST_END, NULL } }; +ATTRIB_MAP_ENTRY attrib_map_to_delete_v30[] = { + { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" }, + { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" }, + { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" }, + { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" }, + { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" }, + { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" }, + { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" }, + { LDAP_ATTR_HOME_PATH, "sambaHomePath" }, + { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" }, + { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" }, + { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" }, + { LDAP_ATTR_USER_SID, LDAP_ATTRIBUTE_SID }, + { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" }, + { LDAP_ATTR_LMPW, "sambaLMPassword" }, + { LDAP_ATTR_NTPW, "sambaNTPassword" }, + { LDAP_ATTR_DOMAIN, "sambaDomainName" }, + { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" }, + { LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" }, + { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" }, + { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" }, + { LDAP_ATTR_PWD_HISTORY, "sambaPasswordHistory" }, + { LDAP_ATTR_LOGON_HOURS, "sambaLogonHours" }, + { LDAP_ATTR_LIST_END, NULL } +}; + /* attributes used for allocating RIDs */ ATTRIB_MAP_ENTRY dominfo_attr_list[] = { @@ -428,6 +477,12 @@ static BOOL fetch_ldap_pw(char **dn, char** pw) char oldval[2048]; /* current largest allowed value is mungeddial */ BOOL existed; + if (attribute == NULL) { + /* This can actually happen for ldapsam_compat where we for + * example don't have a password history */ + return; + } + if (existing != NULL) { existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval)); } else { diff --git a/source/lib/smbrun.c b/source/lib/smbrun.c index 592543bc43b..43cb209174e 100644 --- a/source/lib/smbrun.c +++ b/source/lib/smbrun.c @@ -90,7 +90,7 @@ int smbrun(char *cmd, int *outfd) *outfd = -1; } return errno; - } + } if (pid) { /* @@ -178,3 +178,124 @@ int smbrun(char *cmd, int *outfd) exit(82); return 1; } + + +/**************************************************************************** +run a command being careful about uid/gid handling and putting the output in +outfd (or discard it if outfd is NULL). +sends the provided secret to the child stdin. +****************************************************************************/ + +int smbrunsecret(char *cmd, char *secret) +{ + pid_t pid; + uid_t uid = current_user.uid; + gid_t gid = current_user.gid; + int ifd[2]; + + /* + * Lose any kernel oplock capabilities we may have. + */ + oplock_set_capability(False, False); + + /* build up an input pipe */ + if(pipe(ifd)) { + return -1; + } + + /* in this method we will exec /bin/sh with the correct + arguments, after first setting stdout to point at the file */ + + /* + * We need to temporarily stop CatchChild from eating + * SIGCLD signals as it also eats the exit status code. JRA. + */ + + CatchChildLeaveStatus(); + + if ((pid=sys_fork()) < 0) { + DEBUG(0, ("smbrunsecret: fork failed with error %s\n", strerror(errno))); + CatchChild(); + return errno; + } + + if (pid) { + /* + * Parent. + */ + int status = 0; + pid_t wpid; + + close(ifd[0]); + /* send the secret */ + write(ifd[1], secret, strlen(secret)); + fsync(ifd[1]); + close(ifd[1]); + + /* the parent just waits for the child to exit */ + while((wpid = sys_waitpid(pid, &status, 0)) < 0) { + if(errno == EINTR) { + errno = 0; + continue; + } + break; + } + + CatchChild(); + + if (wpid != pid) { + DEBUG(2, ("waitpid(%d) : %s\n", (int)pid, strerror(errno))); + return -1; + } + +#if defined(WIFEXITED) && defined(WEXITSTATUS) + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } +#endif + + return status; + } + + CatchChild(); + + /* we are in the child. we exec /bin/sh to do the work for us. we + don't directly exec the command we want because it may be a + pipeline or anything else the config file specifies */ + + close(ifd[1]); + close(0); + if (sys_dup2(ifd[0], 0) != 0) { + DEBUG(2,("Failed to create stdin file descriptor\n")); + close(ifd[0]); + exit(80); + } + + /* now completely lose our privileges. This is a fairly paranoid + way of doing it, but it does work on all systems that I know of */ + + become_user_permanently(uid, gid); + + if (getuid() != uid || geteuid() != uid || + getgid() != gid || getegid() != gid) { + /* we failed to lose our privileges - do not execute + the command */ + exit(81); /* we can't print stuff at this stage, + instead use exit codes for debugging */ + } + +#ifndef __INSURE__ + /* close all other file descriptors, leaving only 0, 1 and 2. 0 and + 2 point to /dev/null from the startup code */ + { + int fd; + for (fd = 3; fd < 256; fd++) close(fd); + } +#endif + + execl("/bin/sh", "sh", "-c", cmd, NULL); + + /* not reached */ + exit(82); + return 1; +} diff --git a/source/lib/util.c b/source/lib/util.c index 8d01d9e7c9c..a456395cad1 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -1491,14 +1491,13 @@ BOOL is_in_path(const char *name, name_compare_entry *namelist, BOOL case_sensit pstring last_component; char *p; - DEBUG(8, ("is_in_path: %s\n", name)); - /* if we have no list it's obviously not in the path */ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) { - DEBUG(8,("is_in_path: no name list.\n")); return False; } + DEBUG(8, ("is_in_path: %s\n", name)); + /* Get the last component of the unix name. */ p = strrchr_m(name, '/'); strncpy(last_component, p ? ++p : name, sizeof(last_component)-1); diff --git a/source/lib/util_file.c b/source/lib/util_file.c index bd505ac921c..303d961df57 100644 --- a/source/lib/util_file.c +++ b/source/lib/util_file.c @@ -24,7 +24,6 @@ #define MAP_FAILED ((void *)-1) #endif - static int gotalarm; /*************************************************************** @@ -33,7 +32,7 @@ static int gotalarm; static void gotalarm_sig(void) { - gotalarm = 1; + gotalarm = 1; } /*************************************************************** @@ -43,34 +42,33 @@ static void gotalarm_sig(void) BOOL do_file_lock(int fd, int waitsecs, int type) { - SMB_STRUCT_FLOCK lock; - int ret; - void (*oldsig_handler)(int); - - gotalarm = 0; - oldsig_handler = CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); - - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 1; - lock.l_pid = 0; - - alarm(waitsecs); - /* Note we must *NOT* use sys_fcntl here ! JRA */ - ret = fcntl(fd, SMB_F_SETLKW, &lock); - alarm(0); - CatchSignal(SIGALRM, SIGNAL_CAST oldsig_handler); - - if (gotalarm) { - DEBUG(0, ("do_file_lock: failed to %s file.\n", - type == F_UNLCK ? "unlock" : "lock")); - return False; - } - - return (ret == 0); -} + SMB_STRUCT_FLOCK lock; + int ret; + void (*oldsig_handler)(int); + + gotalarm = 0; + oldsig_handler = CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); + + lock.l_type = type; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + lock.l_pid = 0; + + alarm(waitsecs); + /* Note we must *NOT* use sys_fcntl here ! JRA */ + ret = fcntl(fd, SMB_F_SETLKW, &lock); + alarm(0); + CatchSignal(SIGALRM, SIGNAL_CAST oldsig_handler); + + if (gotalarm) { + DEBUG(0, ("do_file_lock: failed to %s file.\n", + type == F_UNLCK ? "unlock" : "lock")); + return False; + } + return (ret == 0); +} /*************************************************************** Lock an fd. Abandon after waitsecs seconds. @@ -78,21 +76,19 @@ BOOL do_file_lock(int fd, int waitsecs, int type) BOOL file_lock(int fd, int type, int secs, int *plock_depth) { - if (fd < 0) - return False; + if (fd < 0) + return False; - (*plock_depth)++; + (*plock_depth)++; - if ((*plock_depth) == 0) - { - if (!do_file_lock(fd, secs, type)) { - DEBUG(10,("file_lock: locking file failed, error = %s.\n", - strerror(errno))); - return False; - } - } + if ((*plock_depth) == 0) { + if (!do_file_lock(fd, secs, type)) { + DEBUG(10,("file_lock: locking file failed, error = %s.\n", strerror(errno))); + return False; + } + } - return True; + return True; } /*************************************************************** @@ -101,105 +97,107 @@ BOOL file_lock(int fd, int type, int secs, int *plock_depth) BOOL file_unlock(int fd, int *plock_depth) { - BOOL ret=True; + BOOL ret=True; - if(*plock_depth == 1) - ret = do_file_lock(fd, 5, F_UNLCK); + if(*plock_depth == 1) { + ret = do_file_lock(fd, 5, F_UNLCK); + } - (*plock_depth)--; + (*plock_depth)--; - if(!ret) - DEBUG(10,("file_unlock: unlocking file failed, error = %s.\n", - strerror(errno))); - return ret; + if(!ret) { + DEBUG(10,("file_unlock: unlocking file failed, error = %s.\n", strerror(errno))); + } + return ret; } /*************************************************************** - locks a file for enumeration / modification. + Locks a file for enumeration / modification. update to be set = True if modification is required. ****************************************************************/ void *startfilepwent(char *pfile, char *s_readbuf, int bufsize, int *file_lock_depth, BOOL update) { - FILE *fp = NULL; + FILE *fp = NULL; - if (!*pfile) - { - DEBUG(0, ("startfilepwent: No file set\n")); - return (NULL); - } - DEBUG(10, ("startfilepwent: opening file %s\n", pfile)); + if (!*pfile) { + DEBUG(0, ("startfilepwent: No file set\n")); + return (NULL); + } + DEBUG(10, ("startfilepwent: opening file %s\n", pfile)); - fp = sys_fopen(pfile, update ? "r+b" : "rb"); + fp = sys_fopen(pfile, update ? "r+b" : "rb"); - if (fp == NULL) { - DEBUG(0, ("startfilepwent: unable to open file %s\n", pfile)); - return NULL; - } + if (fp == NULL) { + DEBUG(0, ("startfilepwent: unable to open file %s\n", pfile)); + return NULL; + } - /* Set a buffer to do more efficient reads */ - setvbuf(fp, s_readbuf, _IOFBF, bufsize); + /* Set a buffer to do more efficient reads */ + setvbuf(fp, s_readbuf, _IOFBF, bufsize); - if (!file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, file_lock_depth)) - { - DEBUG(0, ("startfilepwent: unable to lock file %s\n", pfile)); - fclose(fp); - return NULL; - } + if (!file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, file_lock_depth)) { + DEBUG(0, ("startfilepwent: unable to lock file %s\n", pfile)); + fclose(fp); + return NULL; + } - /* Make sure it is only rw by the owner */ - chmod(pfile, 0600); + /* Make sure it is only rw by the owner */ + chmod(pfile, 0600); - /* We have a lock on the file. */ - return (void *)fp; + /* We have a lock on the file. */ + return (void *)fp; } /*************************************************************** End enumeration of the file. ****************************************************************/ + void endfilepwent(void *vp, int *file_lock_depth) { - FILE *fp = (FILE *)vp; + FILE *fp = (FILE *)vp; - file_unlock(fileno(fp), file_lock_depth); - fclose(fp); - DEBUG(7, ("endfilepwent: closed file.\n")); + file_unlock(fileno(fp), file_lock_depth); + fclose(fp); + DEBUG(7, ("endfilepwent: closed file.\n")); } /************************************************************************* Return the current position in the file list as an SMB_BIG_UINT. This must be treated as an opaque token. *************************************************************************/ + SMB_BIG_UINT getfilepwpos(void *vp) { - return (SMB_BIG_UINT)sys_ftell((FILE *)vp); + return (SMB_BIG_UINT)sys_ftell((FILE *)vp); } /************************************************************************* Set the current position in the file list from an SMB_BIG_UINT. This must be treated as an opaque token. *************************************************************************/ + BOOL setfilepwpos(void *vp, SMB_BIG_UINT tok) { - return !sys_fseek((FILE *)vp, (SMB_OFF_T)tok, SEEK_SET); + return !sys_fseek((FILE *)vp, (SMB_OFF_T)tok, SEEK_SET); } /************************************************************************* - gets a line out of a file. + Gets a line out of a file. line is of format "xxxx:xxxxxx:xxxxx:". lines with "#" at the front are ignored. *************************************************************************/ + int getfileline(void *vp, char *linebuf, int linebuf_size) { /* Static buffers we will return. */ FILE *fp = (FILE *)vp; unsigned char c; unsigned char *p; - size_t linebuf_len; + size_t linebuf_len; - if (fp == NULL) - { + if (fp == NULL) { DEBUG(0,("getfileline: Bad file pointer.\n")); return -1; } @@ -207,13 +205,11 @@ int getfileline(void *vp, char *linebuf, int linebuf_size) /* * Scan the file, a line at a time. */ - while (!feof(fp)) - { + while (!feof(fp)) { linebuf[0] = '\0'; fgets(linebuf, linebuf_size, fp); - if (ferror(fp)) - { + if (ferror(fp)) { return -1; } @@ -223,47 +219,38 @@ int getfileline(void *vp, char *linebuf, int linebuf_size) */ linebuf_len = strlen(linebuf); - if (linebuf_len == 0) - { + if (linebuf_len == 0) { linebuf[0] = '\0'; return 0; } - if (linebuf[linebuf_len - 1] != '\n') - { + if (linebuf[linebuf_len - 1] != '\n') { c = '\0'; - while (!ferror(fp) && !feof(fp)) - { + while (!ferror(fp) && !feof(fp)) { c = fgetc(fp); - if (c == '\n') - { + if (c == '\n') { break; } } - } - else - { + } else { linebuf[linebuf_len - 1] = '\0'; } #ifdef DEBUG_PASSWORD DEBUG(100, ("getfileline: got line |%s|\n", linebuf)); #endif - if ((linebuf[0] == 0) && feof(fp)) - { + if ((linebuf[0] == 0) && feof(fp)) { DEBUG(4, ("getfileline: end of file reached\n")); return 0; } - if (linebuf[0] == '#' || linebuf[0] == '\0') - { + if (linebuf[0] == '#' || linebuf[0] == '\0') { DEBUG(6, ("getfileline: skipping comment or blank line\n")); continue; } p = (unsigned char *) strchr_m(linebuf, ':'); - if (p == NULL) - { + if (p == NULL) { DEBUG(0, ("getfileline: malformed line entry (no :)\n")); continue; } @@ -272,85 +259,89 @@ int getfileline(void *vp, char *linebuf, int linebuf_size) return -1; } - /**************************************************************************** -read a line from a file with possible \ continuation chars. -Blanks at the start or end of a line are stripped. -The string will be allocated if s2 is NULL + Read a line from a file with possible \ continuation chars. + Blanks at the start or end of a line are stripped. + The string will be allocated if s2 is NULL. ****************************************************************************/ + char *fgets_slash(char *s2,int maxlen,XFILE *f) { - char *s=s2; - int len = 0; - int c; - BOOL start_of_line = True; - - if (x_feof(f)) - return(NULL); - - if (maxlen <2) return(NULL); - - if (!s2) - { - maxlen = MIN(maxlen,8); - s = (char *)malloc(maxlen); - } - - if (!s) return(NULL); - - *s = 0; - - while (len < maxlen-1) - { - c = x_getc(f); - switch (c) - { - case '\r': - break; - case '\n': - while (len > 0 && s[len-1] == ' ') - { - s[--len] = 0; - } - if (len > 0 && s[len-1] == '\\') - { - s[--len] = 0; - start_of_line = True; - break; - } - return(s); - case EOF: - if (len <= 0 && !s2) - SAFE_FREE(s); - return(len>0?s:NULL); - case ' ': - if (start_of_line) - break; - default: - start_of_line = False; - s[len++] = c; - s[len] = 0; - } - if (!s2 && len > maxlen-3) - { - char *t; + char *s=s2; + int len = 0; + int c; + BOOL start_of_line = True; + + if (x_feof(f)) { + return(NULL); + } + + if (maxlen <2) { + return(NULL); + } + + if (!s2) { + maxlen = MIN(maxlen,8); + s = (char *)malloc(maxlen); + } + + if (!s) { + return(NULL); + } + + *s = 0; + + while (len < maxlen-1) { + c = x_getc(f); + switch (c) { + case '\r': + break; + case '\n': + while (len > 0 && s[len-1] == ' ') { + s[--len] = 0; + } + if (len > 0 && s[len-1] == '\\') { + s[--len] = 0; + start_of_line = True; + break; + } + return(s); + case EOF: + if (len <= 0 && !s2) { + SAFE_FREE(s); + } + return(len>0?s:NULL); + case ' ': + if (start_of_line) { + break; + } + default: + start_of_line = False; + s[len++] = c; + s[len] = 0; + } + + if (!s2 && len > maxlen-3) { + char *t; - maxlen *= 2; - t = (char *)Realloc(s,maxlen); - if (!t) { - DEBUG(0,("fgets_slash: failed to expand buffer!\n")); - SAFE_FREE(s); - return(NULL); - } else s = t; - } - } - return(s); + maxlen *= 2; + t = (char *)Realloc(s,maxlen); + if (!t) { + DEBUG(0,("fgets_slash: failed to expand buffer!\n")); + SAFE_FREE(s); + return(NULL); + } else { + s = t; + } + } + } + return(s); } - /**************************************************************************** -load from a pipe into memory + Load from a pipe into memory. ****************************************************************************/ + char *file_pload(char *syscmd, size_t *size) { int fd, n; @@ -359,7 +350,9 @@ char *file_pload(char *syscmd, size_t *size) size_t total; fd = sys_popen(syscmd); - if (fd == -1) return NULL; + if (fd == -1) { + return NULL; + } p = NULL; total = 0; @@ -371,7 +364,9 @@ char *file_pload(char *syscmd, size_t *size) close(fd); SAFE_FREE(p); return NULL; - } else p = tp; + } else { + p = tp; + } memcpy(p+total, buf, n); total += n; } @@ -382,13 +377,15 @@ char *file_pload(char *syscmd, size_t *size) * truncated. */ sys_pclose(fd); - if (size) *size = total; + if (size) { + *size = total; + } return p; } /**************************************************************************** -load a file into memory from a fd. + Load a file into memory from a fd. ****************************************************************************/ char *fd_load(int fd, size_t *size) @@ -396,10 +393,14 @@ char *fd_load(int fd, size_t *size) SMB_STRUCT_STAT sbuf; char *p; - if (sys_fstat(fd, &sbuf) != 0) return NULL; + if (sys_fstat(fd, &sbuf) != 0) { + return NULL; + } p = (char *)malloc(sbuf.st_size+1); - if (!p) return NULL; + if (!p) { + return NULL; + } if (read(fd, p, sbuf.st_size) != sbuf.st_size) { SAFE_FREE(p); @@ -407,79 +408,85 @@ char *fd_load(int fd, size_t *size) } p[sbuf.st_size] = 0; - if (size) *size = sbuf.st_size; + if (size) { + *size = sbuf.st_size; + } return p; } /**************************************************************************** -load a file into memory + Load a file into memory. ****************************************************************************/ + char *file_load(const char *fname, size_t *size) { int fd; char *p; - if (!fname || !*fname) return NULL; + if (!fname || !*fname) { + return NULL; + } fd = open(fname,O_RDONLY); - if (fd == -1) return NULL; + if (fd == -1) { + return NULL; + } p = fd_load(fd, size); - close(fd); - return p; } - /******************************************************************* -mmap (if possible) or read a file + mmap (if possible) or read a file. ********************************************************************/ + void *map_file(char *fname, size_t size) { size_t s2 = 0; void *p = NULL; #ifdef HAVE_MMAP - if (lp_use_mmap()) { - int fd; - fd = open(fname, O_RDONLY, 0); - if (fd == -1) { - DEBUG(2,("Failed to load %s - %s\n", fname, strerror(errno))); - return NULL; - } - p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0); - close(fd); - if (p == MAP_FAILED) { - DEBUG(1,("Failed to mmap %s - %s\n", fname, strerror(errno))); - return NULL; - } + int fd; + fd = open(fname, O_RDONLY, 0); + if (fd == -1) { + DEBUG(2,("map_file: Failed to load %s - %s\n", fname, strerror(errno))); + return NULL; + } + p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0); + close(fd); + if (p == MAP_FAILED) { + DEBUG(1,("map_file: Failed to mmap %s - %s\n", fname, strerror(errno))); + return NULL; } #endif if (!p) { p = file_load(fname, &s2); - if (!p) return NULL; + if (!p) { + return NULL; + } if (s2 != size) { - DEBUG(1,("incorrect size for %s - got %lu expected %lu\n", + DEBUG(1,("map_file: incorrect size for %s - got %lu expected %lu\n", fname, (unsigned long)s2, (unsigned long)size)); - if (p) free(p); + SAFE_FREE(p); return NULL; } } - return p; } - /**************************************************************************** -parse a buffer into lines + Parse a buffer into lines. ****************************************************************************/ + static char **file_lines_parse(char *p, size_t size, int *numlines) { int i; char *s, **ret; - if (!p) return NULL; + if (!p) { + return NULL; + } for (s = p, i=0; s < p+size; s++) { if (s[0] == '\n') i++; @@ -491,7 +498,9 @@ static char **file_lines_parse(char *p, size_t size, int *numlines) return NULL; } memset(ret, 0, sizeof(ret[0])*(i+2)); - if (numlines) *numlines = i; + if (numlines) { + *numlines = i; + } ret[0] = p; for (s = p, i=0; s < p+size; s++) { @@ -500,75 +509,87 @@ static char **file_lines_parse(char *p, size_t size, int *numlines) i++; ret[i] = s+1; } - if (s[0] == '\r') s[0] = 0; + if (s[0] == '\r') { + s[0] = 0; + } } return ret; } - /**************************************************************************** -load a file into memory and return an array of pointers to lines in the file -must be freed with file_lines_free(). + Load a file into memory and return an array of pointers to lines in the file + must be freed with file_lines_free(). ****************************************************************************/ + char **file_lines_load(const char *fname, int *numlines) { char *p; size_t size; p = file_load(fname, &size); - if (!p) return NULL; + if (!p) { + return NULL; + } return file_lines_parse(p, size, numlines); } /**************************************************************************** -load a fd into memory and return an array of pointers to lines in the file -must be freed with file_lines_free(). If convert is true calls unix_to_dos on -the list. + Load a fd into memory and return an array of pointers to lines in the file + must be freed with file_lines_free(). If convert is true calls unix_to_dos on + the list. ****************************************************************************/ + char **fd_lines_load(int fd, int *numlines) { char *p; size_t size; p = fd_load(fd, &size); - if (!p) return NULL; + if (!p) { + return NULL; + } return file_lines_parse(p, size, numlines); } - /**************************************************************************** -load a pipe into memory and return an array of pointers to lines in the data -must be freed with file_lines_free(). + Load a pipe into memory and return an array of pointers to lines in the data + must be freed with file_lines_free(). ****************************************************************************/ + char **file_lines_pload(char *syscmd, int *numlines) { char *p; size_t size; p = file_pload(syscmd, &size); - if (!p) return NULL; + if (!p) { + return NULL; + } return file_lines_parse(p, size, numlines); } /**************************************************************************** -free lines loaded with file_lines_load + Free lines loaded with file_lines_load. ****************************************************************************/ + void file_lines_free(char **lines) { - if (!lines) return; + if (!lines) { + return; + } SAFE_FREE(lines[0]); SAFE_FREE(lines); } - /**************************************************************************** -take a lislist of lines and modify them to produce a list where \ continues -a line + Take a list of lines and modify them to produce a list where \ continues + a line. ****************************************************************************/ + void file_lines_slashcont(char **lines) { int i, j; @@ -579,8 +600,12 @@ void file_lines_slashcont(char **lines) lines[i][len-1] = ' '; if (lines[i+1]) { char *p = &lines[i][len]; - while (p < lines[i+1]) *p++ = ' '; - for (j = i+1; lines[j]; j++) lines[j] = lines[j+1]; + while (p < lines[i+1]) { + *p++ = ' '; + } + for (j = i+1; lines[j]; j++) { + lines[j] = lines[j+1]; + } } } else { i++; @@ -588,9 +613,10 @@ void file_lines_slashcont(char **lines) } } -/* - save a lump of data into a file. Mostly used for debugging -*/ +/**************************************************************************** + Save a lump of data into a file. Mostly used for debugging. +****************************************************************************/ + BOOL file_save(const char *fname, void *packet, size_t length) { int fd; diff --git a/source/lib/util_str.c b/source/lib/util_str.c index 6eee62c14aa..65a616ad419 100644 --- a/source/lib/util_str.c +++ b/source/lib/util_str.c @@ -134,17 +134,20 @@ char **toktocliplist(int *ctok, const char *sep) *ctok=ictok; s=(char *)last_ptr; - if (!(ret=iret=malloc(ictok*sizeof(char *)))) + if (!(ret=iret=malloc((ictok+1)*sizeof(char *)))) return NULL; while(ictok--) { *iret++=s; - while(*s++) - ; - while(!*s) - s++; + if (ictok > 0) { + while(*s++) + ; + while(!*s) + s++; + } } + ret[*ctok] = NULL; return ret; } diff --git a/source/lib/util_uuid.c b/source/lib/util_uuid.c index 8f86c2109ea..df70740b33c 100644 --- a/source/lib/util_uuid.c +++ b/source/lib/util_uuid.c @@ -29,11 +29,11 @@ void smb_uuid_pack(const struct uuid uu, UUID_FLAT *ptr) { - SIVAL(ptr, 0, uu.time_low); - SSVAL(ptr, 4, uu.time_mid); - SSVAL(ptr, 6, uu.time_hi_and_version); - memcpy(ptr+8, uu.clock_seq, 2); - memcpy(ptr+10, uu.node, 6); + SIVAL(ptr->info, 0, uu.time_low); + SSVAL(ptr->info, 4, uu.time_mid); + SSVAL(ptr->info, 6, uu.time_hi_and_version); + memcpy(ptr->info+8, uu.clock_seq, 2); + memcpy(ptr->info+10, uu.node, 6); } void smb_uuid_unpack(const UUID_FLAT in, struct uuid *uu) @@ -96,6 +96,7 @@ BOOL smb_string_to_uuid(const char *in, struct uuid* uu) const char *ptr = in; char *end = (char *)in; int i; + unsigned v1, v2; if (!in || !uu) goto out; @@ -111,61 +112,22 @@ BOOL smb_string_to_uuid(const char *in, struct uuid* uu) if ((end - ptr) != 4 || *end != '-') goto out; ptr = (end + 1); - for (i = 0; i < 2; i++) { - int adj = 0; - if (*ptr >= '0' && *ptr <= '9') { - adj = '0'; - } else if (*ptr >= 'a' && *ptr <= 'f') { - adj = 'a'; - } else if (*ptr >= 'A' && *ptr <= 'F') { - adj = 'A'; - } else { - goto out; - } - uu->clock_seq[i] = (*ptr - adj) << 4; - ptr++; - - if (*ptr >= '0' && *ptr <= '9') { - adj = '0'; - } else if (*ptr >= 'a' && *ptr <= 'f') { - adj = 'a'; - } else if (*ptr >= 'A' && *ptr <= 'F') { - adj = 'A'; - } else { - goto out; - } - uu->clock_seq[i] |= (*ptr - adj); - ptr++; + if (sscanf(ptr, "%02x%02x", &v1, &v2) != 2) { + goto out; } + uu->clock_seq[0] = v1; + uu->clock_seq[1] = v2; + ptr += 4; if (*ptr != '-') goto out; ptr++; for (i = 0; i < 6; i++) { - int adj = 0; - if (*ptr >= '0' && *ptr <= '9') { - adj = '0'; - } else if (*ptr >= 'a' && *ptr <= 'f') { - adj = 'a'; - } else if (*ptr >= 'A' && *ptr <= 'F') { - adj = 'A'; - } else { - goto out; - } - uu->node[i] = (*ptr - adj) << 4; - ptr++; - - if (*ptr >= '0' && *ptr <= '9') { - adj = '0'; - } else if (*ptr >= 'a' && *ptr <= 'f') { - adj = 'a'; - } else if (*ptr >= 'A' && *ptr <= 'F') { - adj = 'A'; - } else { + if (sscanf(ptr, "%02x", &v1) != 1) { goto out; } - uu->node[i] |= (*ptr - adj); - ptr++; + uu->node[i] = v1; + ptr += 2; } ret = True; diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c index 97b895a2418..327a76826ef 100644 --- a/source/libads/kerberos.c +++ b/source/libads/kerberos.c @@ -146,7 +146,8 @@ int ads_kdestroy(const char *cc_name) krb5_ccache cc = NULL; if ((code = krb5_init_context (&ctx))) { - DEBUG(3, ("ads_kdestroy: kdb5_init_context rc=%d\n", code)); + DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", + error_message(code))); return code; } @@ -157,15 +158,16 @@ int ads_kdestroy(const char *cc_name) } } else { if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) { - DEBUG(3, ("ads_kdestroy: krb5_cc_resolve rc=%d\n", - code)); + DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n", + error_message(code))); krb5_free_context(ctx); return code; } } if ((code = krb5_cc_destroy (ctx, cc))) { - DEBUG(3, ("ads_kdestroy: krb5_cc_destroy rc=%d\n", code)); + DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", + error_message(code))); } krb5_free_context (ctx); diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c index 559538aac9b..4ff60c1b1ca 100644 --- a/source/libsmb/cliconnect.c +++ b/source/libsmb/cliconnect.c @@ -668,11 +668,16 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use DATA_BLOB key = data_blob(ntlmssp_state->session_key.data, ntlmssp_state->session_key.length); DATA_BLOB null_blob = data_blob(NULL, 0); + BOOL res; fstrcpy(cli->server_domain, ntlmssp_state->server_domain); cli_set_session_key(cli, ntlmssp_state->session_key); - if (cli_simple_set_signing(cli, key, null_blob)) { + res = cli_simple_set_signing(cli, key, null_blob); + + data_blob_free(&key); + + if (res) { /* 'resign' the last message, so we get the right sequence numbers for checking the first reply from the server */ @@ -1133,6 +1138,7 @@ BOOL cli_negprot(struct cli_state *cli) cli->use_spnego = False; cli->sec_mode = SVAL(cli->inbuf,smb_vwv1); cli->max_xmit = SVAL(cli->inbuf,smb_vwv2); + cli->max_mux = SVAL(cli->inbuf, smb_vwv3); cli->sesskey = IVAL(cli->inbuf,smb_vwv6); cli->serverzone = SVALS(cli->inbuf,smb_vwv10); cli->serverzone *= 60; diff --git a/source/libsmb/clifile.c b/source/libsmb/clifile.c index 398c7cc4f0a..ff0edc6bb4e 100644 --- a/source/libsmb/clifile.c +++ b/source/libsmb/clifile.c @@ -983,6 +983,47 @@ BOOL cli_getatr(struct cli_state *cli, const char *fname, } /**************************************************************************** + Do a SMBsetattrE call. +****************************************************************************/ + +BOOL cli_setattrE(struct cli_state *cli, int fd, + time_t c_time, time_t a_time, time_t m_time) + +{ + char *p; + + memset(cli->outbuf,'\0',smb_size); + memset(cli->inbuf,'\0',smb_size); + + set_message(cli->outbuf,7,0,True); + + SCVAL(cli->outbuf,smb_com,SMBsetattrE); + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0, fd); + put_dos_date3(cli->outbuf,smb_vwv1, c_time); + put_dos_date3(cli->outbuf,smb_vwv3, a_time); + put_dos_date3(cli->outbuf,smb_vwv5, m_time); + + p = smb_buf(cli->outbuf); + *p++ = 4; + + cli_setup_bcc(cli, p); + + cli_send_smb(cli); + if (!cli_receive_smb(cli)) { + return False; + } + + if (cli_is_error(cli)) { + return False; + } + + return True; +} + +/**************************************************************************** Do a SMBsetatr call. ****************************************************************************/ diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c index 5fcde4654ad..f7f84f1e297 100644 --- a/source/libsmb/clikrb5.c +++ b/source/libsmb/clikrb5.c @@ -190,6 +190,7 @@ krb5_error_code rc; int num_kdcs, i; struct sockaddr *sa; + struct addrinfo *ai; *addr_pp = NULL; *naddrs = 0; @@ -219,10 +220,19 @@ return -1; } + *addr_pp = malloc(sizeof(struct sockaddr) * num_kdcs); memset(*addr_pp, '\0', sizeof(struct sockaddr) * num_kdcs ); for (i = 0; i < num_kdcs && (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); i++) { - if (hinfo->ai->ai_family == AF_INET) + +#if defined(HAVE_KRB5_KRBHST_GET_ADDRINFO) + rc = krb5_krbhst_get_addrinfo(ctx, hinfo, &ai); + if (rc) { + DEBUG(0,("krb5_krbhst_get_addrinfo failed: %s\n", error_message(rc))); + continue; + } +#endif + if (hinfo->ai && hinfo->ai->ai_family == AF_INET) memcpy(&sa[i], hinfo->ai->ai_addr, sizeof(struct sockaddr)); } @@ -420,14 +430,8 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset, failed: if ( context ) { -/* 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) -#if 0 /* redisabled by gd :) at least until any official heimdal version has it fixed. */ krb5_cc_close(context, ccdef); -#endif if (auth_context) krb5_auth_con_free(context, auth_context); krb5_free_context(context); diff --git a/source/libsmb/cliquota.c b/source/libsmb/cliquota.c index ed808aa1f5c..af8b4422b78 100644 --- a/source/libsmb/cliquota.c +++ b/source/libsmb/cliquota.c @@ -22,13 +22,13 @@ BOOL cli_get_quota_handle(struct cli_state *cli, int *quota_fnum) { - *quota_fnum = cli_nt_create_full(cli, FAKE_FILE_NAME_QUOTA, + *quota_fnum = cli_nt_create_full(cli, FAKE_FILE_NAME_QUOTA_WIN32, 0x00000016, DESIRED_ACCESS_PIPE, 0x00000000, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x00000000, 0x03); if (*quota_fnum == (-1)) { - return False; + return False; } return True; diff --git a/source/libsmb/clireadwrite.c b/source/libsmb/clireadwrite.c index 8eac7d07d8b..3f14e530943 100644 --- a/source/libsmb/clireadwrite.c +++ b/source/libsmb/clireadwrite.c @@ -325,10 +325,16 @@ ssize_t cli_write(struct cli_state *cli, int bwritten = 0; int issued = 0; int received = 0; - int mpx = MAX(cli->max_mux-1, 1); + int mpx = 1; int block = cli->max_xmit - (smb_size+32); int blocks = (size + (block-1)) / block; + if(cli->max_mux > 1) { + mpx = cli->max_mux-1; + } else { + mpx = 1; + } + while (received < blocks) { while ((issued - received < mpx) && (issued < blocks)) { diff --git a/source/locking/locking.c b/source/locking/locking.c index 8f53b55fc54..d4e8c493d50 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -1043,18 +1043,6 @@ int get_deferred_opens(connection_struct *conn, 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 && @@ -1064,7 +1052,6 @@ static BOOL deferred_open_entries_identical( deferred_open_entry *e1, deferred_o e1->time.tv_usec == e2->time.tv_usec); } - /******************************************************************* Delete a specific deferred open entry. Ignore if no entry deleted. diff --git a/source/modules/weird.c b/source/modules/weird.c index 444853f3831..3c59fd9d61f 100644 --- a/source/modules/weird.c +++ b/source/modules/weird.c @@ -31,7 +31,7 @@ static struct { {0, NULL} }; -static size_t weird_pull(void *cd, char **inbuf, size_t *inbytesleft, +static size_t weird_pull(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { while (*inbytesleft >= 1 && *outbytesleft >= 2) { @@ -74,7 +74,7 @@ static size_t weird_pull(void *cd, char **inbuf, size_t *inbytesleft, return 0; } -static size_t weird_push(void *cd, char **inbuf, size_t *inbytesleft, +static size_t weird_push(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { int ir_count=0; diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c index 880de7f91bf..f8006a22a9e 100644 --- a/source/nmbd/nmbd.c +++ b/source/nmbd/nmbd.c @@ -29,6 +29,8 @@ int global_nmb_port = -1; extern BOOL global_in_nmbd; +extern BOOL override_logfile; + /* are we running as a daemon ? */ static BOOL is_daemon; @@ -623,8 +625,10 @@ static BOOL open_sockets(BOOL isdaemon, int port) sys_srandom(time(NULL) ^ sys_getpid()); - slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", dyn_LOGFILEBASE); - lp_set_logfile(logfile); + if (!override_logfile) { + slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", dyn_LOGFILEBASE); + lp_set_logfile(logfile); + } fault_setup((void (*)(void *))fault_continue ); diff --git a/source/nmbd/nmbd_workgroupdb.c b/source/nmbd/nmbd_workgroupdb.c index 8880cb58bb4..8f3ae36b65d 100644 --- a/source/nmbd/nmbd_workgroupdb.c +++ b/source/nmbd/nmbd_workgroupdb.c @@ -41,6 +41,27 @@ static void add_workgroup(struct subnet_record *subrec, struct work_record *work } /**************************************************************************** + Copy name to unstring. Used by create_workgroup() and find_workgroup_on_subnet(). +**************************************************************************/ + +static void name_to_unstring(unstring unname, const char *name) +{ + nstring nname; + + errno = 0; + push_ascii_nstring(nname, name); + if (errno == E2BIG) { + unstring tname; + pull_ascii_nstring(tname, sizeof(tname), nname); + unstrcpy(unname, tname); + DEBUG(0,("name_to_nstring: workgroup name %s is too long. Truncating to %s\n", + name, tname)); + } else { + unstrcpy(unname, name); + } +} + +/**************************************************************************** Create an empty workgroup. **************************************************************************/ @@ -48,8 +69,6 @@ static struct work_record *create_workgroup(const char *name, int ttl) { struct work_record *work; struct subnet_record *subrec; - nstring nname; - int t = -1; if((work = (struct work_record *)malloc(sizeof(*work))) == NULL) { @@ -58,17 +77,8 @@ static struct work_record *create_workgroup(const char *name, int ttl) } memset((char *)work, '\0', sizeof(*work)); - errno = 0; - push_ascii_nstring(nname, name); - if (errno == E2BIG) { - unstring tname; - pull_ascii_nstring(tname, sizeof(tname), nname); - unstrcpy(work->work_group,tname); - DEBUG(0,("create_workgroup: workgroup name %s is too long. Truncating to %s\n", - name, tname)); - } else { - unstrcpy(work->work_group,name); - } + name_to_unstring(work->work_group, name); + work->serverlist = NULL; work->RunningElection = False; @@ -157,12 +167,15 @@ struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec, const char *name) { struct work_record *ret; - + unstring un_name; + DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ", name, subrec->subnet_name)); + name_to_unstring(un_name, name); + for (ret = subrec->workgrouplist; ret; ret = ret->next) { - if (strequal(ret->work_group,name)) { + if (strequal(ret->work_group,un_name)) { DEBUGADD(4, ("found.\n")); return(ret); } diff --git a/source/nsswitch/pam_winbind.c b/source/nsswitch/pam_winbind.c index 123f6703665..64e21738221 100644 --- a/source/nsswitch/pam_winbind.c +++ b/source/nsswitch/pam_winbind.c @@ -45,6 +45,8 @@ static int _pam_parse(int argc, const char **argv) ctrl |= WINBIND_TRY_FIRST_PASS_ARG; else if (!strcasecmp(*argv, "unknown_ok")) ctrl |= WINBIND_UNKNOWN_OK_ARG; + else if (!strncasecmp(*argv, "required_membership", strlen("required_membership"))) + ctrl |= WINBIND_REQUIRED_MEMBERSHIP; else { _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); } @@ -148,7 +150,7 @@ static int pam_winbind_request_log(enum winbindd_cmd req_type, switch (retval) { case PAM_AUTH_ERR: /* incorrect password */ - _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", user); + _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password or invalid membership)", user); return retval; case PAM_ACCT_EXPIRED: /* account expired */ @@ -174,7 +176,7 @@ static int pam_winbind_request_log(enum winbindd_cmd req_type, case PAM_SUCCESS: if (req_type == WINBINDD_PAM_AUTH) { /* Otherwise, the authentication looked good */ - _pam_log(LOG_NOTICE, "user '%s' granted acces", user); + _pam_log(LOG_NOTICE, "user '%s' granted access", user); } else if (req_type == WINBINDD_PAM_CHAUTHTOK) { /* Otherwise, the authentication looked good */ _pam_log(LOG_NOTICE, "user '%s' password changed", user); @@ -192,7 +194,7 @@ static int pam_winbind_request_log(enum winbindd_cmd req_type, } /* talk to winbindd */ -static int winbind_auth_request(const char *user, const char *pass, int ctrl) +static int winbind_auth_request(const char *user, const char *pass, const char *member, int ctrl) { struct winbindd_request request; struct winbindd_response response; @@ -204,7 +206,35 @@ static int winbind_auth_request(const char *user, const char *pass, int ctrl) strncpy(request.data.auth.pass, pass, sizeof(request.data.auth.pass)-1); - + + if (member == NULL ) + return pam_winbind_request_log(WINBINDD_PAM_AUTH, &request, &response, ctrl, user); + + /* lookup name? */ + if (!strncmp("S-", member, 2) == 0) { + + struct winbindd_request request; + struct winbindd_response response; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (ctrl & WINBIND_DEBUG_ARG) + _pam_log(LOG_DEBUG, "no sid given, looking up: %s\n", member); + + /* fortunatly winbindd can handle non-separated names */ + strcpy(request.data.name.name, member); + + if (pam_winbind_request_log(WINBINDD_LOOKUPNAME, &request, &response, ctrl, user)) { + _pam_log(LOG_INFO, "could not lookup name: %s\n", member); + return PAM_AUTH_ERR; + } + + member = strdup(response.data.sid.sid); + } + + strncpy(request.data.auth.required_membership_sid, member, + sizeof(request.data.auth.required_membership_sid)-1); return pam_winbind_request_log(WINBINDD_PAM_AUTH, &request, &response, ctrl, user); } @@ -419,7 +449,9 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, { const char *username; const char *password; + const char *member = NULL; int retval = PAM_AUTH_ERR; + int i; /* parse arguments */ int ctrl = _pam_parse(argc, argv); @@ -453,8 +485,25 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, #endif } + /* Retrieve membership-string here */ + for ( i=0; i<argc; i++ ) { + + if (!strncmp(argv[i], "required_membership", strlen("required_membership"))) { + + char *p; + char *parm = strdup(argv[i]); + + if ( (p = strchr( parm, '=' )) == NULL) { + _pam_log(LOG_INFO, "no \"=\" delimiter for \"required_membership\" found\n"); + break; + } + + member = strdup(p+1); + } + } + /* Now use the username to look up password */ - return winbind_auth_request(username, password, ctrl); + return winbind_auth_request(username, password, member, ctrl); } PAM_EXTERN @@ -502,7 +551,7 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, return PAM_USER_UNKNOWN; case 0: /* Otherwise, the authentication looked good */ - _pam_log(LOG_NOTICE, "user '%s' granted acces", username); + _pam_log(LOG_NOTICE, "user '%s' granted access", username); return PAM_SUCCESS; default: /* we don't know anything about this return value */ @@ -546,6 +595,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, /* <DO NOT free() THESE> */ const char *user; + const char *member = NULL; char *pass_old, *pass_new; /* </DO NOT free() THESE> */ @@ -606,7 +656,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, } /* verify that this is the password for this user */ - retval = winbind_auth_request(user, pass_old, ctrl); + retval = winbind_auth_request(user, pass_old, member, ctrl); if (retval != PAM_ACCT_EXPIRED && retval != PAM_AUTHTOK_EXPIRED diff --git a/source/nsswitch/pam_winbind.h b/source/nsswitch/pam_winbind.h index 0afcceb6aa2..7cae477714b 100644 --- a/source/nsswitch/pam_winbind.h +++ b/source/nsswitch/pam_winbind.h @@ -82,6 +82,7 @@ do { \ #define WINBIND_TRY_FIRST_PASS_ARG (1<<3) #define WINBIND_USE_FIRST_PASS_ARG (1<<4) #define WINBIND__OLD_PASSWORD (1<<5) +#define WINBIND_REQUIRED_MEMBERSHIP (1<<6) /* * here is the string to inform the user that the new passwords they diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c index 0028982d201..b6a09bf2a1f 100644 --- a/source/nsswitch/wbinfo.c +++ b/source/nsswitch/wbinfo.c @@ -398,27 +398,6 @@ static BOOL wbinfo_sid_to_uid(char *sid) ZERO_STRUCT(request); ZERO_STRUCT(response); - /* First see whether the SID is actually a user -- otherwise - * winbind might end up a uid number for a group SID and this - * is asking for trouble later. */ - - fstrcpy(request.data.sid, sid); - - if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response) != - NSS_STATUS_SUCCESS) { - d_printf("Could not lookup sid %s\n", sid); - return False; - } - - if (response.data.name.type != SID_NAME_USER) { - d_printf("SID is of type %s\n", - sid_type_lookup(response.data.name.type)); - return False; - } - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - /* Send request */ fstrcpy(request.data.sid, sid); @@ -442,26 +421,6 @@ static BOOL wbinfo_sid_to_gid(char *sid) ZERO_STRUCT(request); ZERO_STRUCT(response); - /* First see whether the SID is actually a group -- otherwise - * winbind might end up a gid number for a user SID and this - * is asking for trouble later. */ - - fstrcpy(request.data.sid, sid); - - if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response) != - NSS_STATUS_SUCCESS) { - d_printf("Could not lookup sid %s\n", sid); - return False; - } - - if ((response.data.name.type != SID_NAME_DOM_GRP) && - (response.data.name.type != SID_NAME_ALIAS) && - (response.data.name.type != SID_NAME_WKN_GRP)) { - d_printf("SID is of type %s\n", - sid_type_lookup(response.data.name.type)); - return False; - } - /* Send request */ fstrcpy(request.data.sid, sid); diff --git a/source/nsswitch/winbind_nss_linux.c b/source/nsswitch/winbind_nss_linux.c index ae2bcc7ade9..0ea5db74da6 100644 --- a/source/nsswitch/winbind_nss_linux.c +++ b/source/nsswitch/winbind_nss_linux.c @@ -833,25 +833,40 @@ _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start, /* Skip primary group */ - if (gid_list[i] == group) continue; - - /* Add to buffer */ + if (gid_list[i] == group) { + continue; + } - if (*start == *size && limit <= 0) { - (*groups) = realloc( - (*groups), (2 * (*size) + 1) * sizeof(**groups)); - if (! *groups) goto done; - *size = 2 * (*size) + 1; + /* Filled buffer ? If so, resize. */ + + if (*start == *size) { + long int newsize; + gid_t *newgroups; + + newsize = 2 * (*size); + if (limit > 0) { + if (*size == limit) { + goto done; + } + if (newsize > limit) { + newsize = limit; + } + } + + newgroups = realloc((*groups), newsize * sizeof(**groups)); + if (!newgroups) { + *errnop = ENOMEM; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + *groups = newgroups; + *size = newsize; } - if (*start == *size) goto done; + /* Add to buffer */ (*groups)[*start] = gid_list[i]; *start += 1; - - /* Filled buffer? */ - - if (*start == limit) goto done; } } diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c index d08aa84face..455fb74f171 100644 --- a/source/nsswitch/winbindd.c +++ b/source/nsswitch/winbindd.c @@ -28,6 +28,8 @@ BOOL opt_nocache = False; BOOL opt_dual_daemon = True; +extern BOOL override_logfile; + /* Reload configuration */ static BOOL reload_services_file(void) @@ -587,6 +589,7 @@ static void process_loop(void) int maxfd, listen_sock, listen_priv_sock, selret; struct timeval timeout; + again: /* Handle messages */ message_dispatch(); @@ -715,6 +718,15 @@ static void process_loop(void) for (state = winbindd_client_list(); state; state = state->next) { + /* Data available for writing */ + + if (FD_ISSET(state->sock, &w_fds)) + client_write(state); + } + + for (state = winbindd_client_list(); state; + state = state->next) { + /* Data available for reading */ if (FD_ISSET(state->sock, &r_fds)) { @@ -747,13 +759,10 @@ static void process_loop(void) if (state->read_buf_len == sizeof(state->request)) { winbind_process_packet(state); + winbindd_demote_client(state); + goto again; } } - - /* Data available for writing */ - - if (FD_ISSET(state->sock, &w_fds)) - client_write(state); } } @@ -846,8 +855,10 @@ int main(int argc, char **argv) exit(1); } - pstr_sprintf(logfile, "%s/log.winbindd", dyn_LOGFILEBASE); - lp_set_logfile(logfile); + if (!override_logfile) { + pstr_sprintf(logfile, "%s/log.winbindd", dyn_LOGFILEBASE); + lp_set_logfile(logfile); + } setup_logging("winbindd", log_stdout); reopen_logs(); diff --git a/source/nsswitch/winbindd_cache.c b/source/nsswitch/winbindd_cache.c index b81f8ecd45a..493255a5a65 100644 --- a/source/nsswitch/winbindd_cache.c +++ b/source/nsswitch/winbindd_cache.c @@ -609,7 +609,6 @@ static void wcache_save_name_to_sid(struct winbindd_domain *domain, { struct cache_entry *centry; fstring uname; - fstring sid_string; centry = centry_start(domain, status); if (!centry) @@ -619,7 +618,8 @@ static void wcache_save_name_to_sid(struct winbindd_domain *domain, fstrcpy(uname, name); strupper_m(uname); centry_end(centry, "NS/%s/%s", domain_name, uname); - DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname, sid_string)); + DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname, + sid_string_static(sid))); centry_free(centry); } diff --git a/source/nsswitch/winbindd_dual.c b/source/nsswitch/winbindd_dual.c index a9796afa367..d4ec6e586db 100644 --- a/source/nsswitch/winbindd_dual.c +++ b/source/nsswitch/winbindd_dual.c @@ -155,7 +155,7 @@ void do_dual_daemon(void) dual_daemon_pipe = fdpair[1]; state.sock = fdpair[0]; - if (fork() != 0) { + if (sys_fork() != 0) { close(fdpair[0]); return; } diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c index ca7f72d0178..a3b826278b5 100644 --- a/source/nsswitch/winbindd_group.c +++ b/source/nsswitch/winbindd_group.c @@ -495,8 +495,6 @@ enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state) The dispinfo_ndx field is incremented to the index of the next group to fetch. Return True if some groups were returned, False otherwise. */ -#define MAX_FETCH_SAM_ENTRIES 100 - static BOOL get_sam_group_entries(struct getent_state *ent) { NTSTATUS status; @@ -925,14 +923,11 @@ static void add_gid_to_array_unique(gid_t gid, gid_t **gids, int *num) { int i; - if ((*num) >= groups_max()) - return; - for (i=0; i<*num; i++) { if ((*gids)[i] == gid) return; } - + *gids = Realloc(*gids, (*num+1) * sizeof(gid_t)); if (*gids == NULL) diff --git a/source/nsswitch/winbindd_sid.c b/source/nsswitch/winbindd_sid.c index 61da9b3d92f..c6e503bef39 100644 --- a/source/nsswitch/winbindd_sid.c +++ b/source/nsswitch/winbindd_sid.c @@ -119,7 +119,7 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state) enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) { DOM_SID sid; - uint32 flags = 0x0; + NTSTATUS result; /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; @@ -166,8 +166,7 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) /* But first check and see if we don't already have a mapping */ - flags = ID_QUERY_ONLY; - if ( NT_STATUS_IS_OK(idmap_sid_to_uid(&sid, &(state->response.data.uid), flags)) ) + if ( NT_STATUS_IS_OK(idmap_sid_to_uid(&sid, &(state->response.data.uid), ID_QUERY_ONLY)) ) return WINBINDD_OK; /* now fall back to the hard way */ @@ -191,17 +190,37 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) } - if ( state->request.flags & WBFLAG_QUERY_ONLY ) - flags = ID_QUERY_ONLY; - /* Find uid for this sid and return it */ - - if ( !NT_STATUS_IS_OK(idmap_sid_to_uid(&sid, &(state->response.data.uid), flags)) ) { - DEBUG(1, ("Could not get uid for sid %s\n", state->request.data.sid)); + + result = idmap_sid_to_uid(&sid, &(state->response.data.uid), + ID_QUERY_ONLY); + + if (NT_STATUS_IS_OK(result)) + return WINBINDD_OK; + + if (state->request.flags & WBFLAG_QUERY_ONLY) return WINBINDD_ERROR; + + /* The query-only did not work, allocate a new uid *if* it's a user */ + + { + fstring dom_name, name; + enum SID_NAME_USE type; + + if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type)) + return WINBINDD_ERROR; + + if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) + return WINBINDD_ERROR; } + + result = idmap_sid_to_uid(&sid, &(state->response.data.uid), 0); - return WINBINDD_OK; + if (NT_STATUS_IS_OK(result)) + return WINBINDD_OK; + + DEBUG(1, ("Could not get uid for sid %s\n", state->request.data.sid)); + return WINBINDD_ERROR; } /* Convert a sid to a gid. We assume we only have one rid attached to the @@ -210,7 +229,7 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) { DOM_SID sid; - uint32 flags = 0x0; + NTSTATUS result; /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; @@ -256,8 +275,7 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) /* But first check and see if we don't already have a mapping */ - flags = ID_QUERY_ONLY; - if ( NT_STATUS_IS_OK(idmap_sid_to_gid(&sid, &(state->response.data.gid), flags)) ) + if ( NT_STATUS_IS_OK(idmap_sid_to_gid(&sid, &(state->response.data.gid), ID_QUERY_ONLY)) ) return WINBINDD_OK; /* now fall back to the hard way */ @@ -281,16 +299,38 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) } - if ( state->request.flags & WBFLAG_QUERY_ONLY ) - flags = ID_QUERY_ONLY; - /* Find gid for this sid and return it */ - if ( !NT_STATUS_IS_OK(idmap_sid_to_gid(&sid, &(state->response.data.gid), flags)) ) { - DEBUG(1, ("Could not get gid for sid %s\n", state->request.data.sid)); + + result = idmap_sid_to_gid(&sid, &(state->response.data.gid), + ID_QUERY_ONLY); + + if (NT_STATUS_IS_OK(result)) + return WINBINDD_OK; + + if (state->request.flags & WBFLAG_QUERY_ONLY) return WINBINDD_ERROR; + + /* The query-only did not work, allocate a new gid *if* it's a group */ + + { + fstring dom_name, name; + enum SID_NAME_USE type; + + if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type)) + return WINBINDD_ERROR; + + if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && + (type != SID_NAME_WKN_GRP)) + return WINBINDD_ERROR; } + + result = idmap_sid_to_gid(&sid, &(state->response.data.gid), 0); - return WINBINDD_OK; + if (NT_STATUS_IS_OK(result)) + return WINBINDD_OK; + + DEBUG(1, ("Could not get gid for sid %s\n", state->request.data.sid)); + return WINBINDD_ERROR; } /* Convert a uid to a sid */ diff --git a/source/nsswitch/winbindd_user.c b/source/nsswitch/winbindd_user.c index 795d657aae7..6f5a86f43ae 100644 --- a/source/nsswitch/winbindd_user.c +++ b/source/nsswitch/winbindd_user.c @@ -385,8 +385,6 @@ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state) field is incremented to the index of the next user to fetch. Return True if some users were returned, False otherwise. */ -#define MAX_FETCH_SAM_ENTRIES 100 - static BOOL get_sam_user_entries(struct getent_state *ent) { NTSTATUS status; diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c index faa6e8d8da4..a9197d35616 100644 --- a/source/nsswitch/winbindd_util.c +++ b/source/nsswitch/winbindd_util.c @@ -736,6 +736,14 @@ void winbindd_remove_client(struct winbindd_cli_state *cli) _num_clients--; } +/* Demote a client to be the last in the list */ + +void winbindd_demote_client(struct winbindd_cli_state *cli) +{ + struct winbindd_cli_state *tmp; + DLIST_DEMOTE(_client_list, cli, tmp); +} + /* Close all open clients */ void winbindd_kill_all_clients(void) diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 14981b97c42..24811af37dd 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -156,6 +156,7 @@ typedef struct char *szAddMachineScript; char *szShutdownScript; char *szAbortShutdownScript; + char *szCheckPasswordScript; char *szWINSHook; char *szWINSPartners; char *szUtmpDir; @@ -811,6 +812,7 @@ static struct parm_struct parm_table[] = { {"passwd chat", P_STRING, P_GLOBAL, &Globals.szPasswdChat, NULL, NULL, FLAG_ADVANCED}, {"passwd chat debug", P_BOOL, P_GLOBAL, &Globals.bPasswdChatDebug, NULL, NULL, FLAG_ADVANCED}, {"passwd chat timeout", P_INTEGER, P_GLOBAL, &Globals.iPasswdChatTimeout, NULL, NULL, FLAG_ADVANCED}, + {"check password script", P_STRING, P_GLOBAL, &Globals.szCheckPasswordScript, NULL, NULL, FLAG_ADVANCED}, {"username map", P_STRING, P_GLOBAL, &Globals.szUsernameMap, NULL, NULL, FLAG_ADVANCED}, {"password level", P_INTEGER, P_GLOBAL, &Globals.pwordlevel, NULL, NULL, FLAG_ADVANCED}, {"username level", P_INTEGER, P_GLOBAL, &Globals.unamelevel, NULL, NULL, FLAG_ADVANCED}, @@ -1678,6 +1680,8 @@ FN_GLOBAL_STRING(lp_addmachine_script, &Globals.szAddMachineScript) FN_GLOBAL_STRING(lp_shutdown_script, &Globals.szShutdownScript) FN_GLOBAL_STRING(lp_abort_shutdown_script, &Globals.szAbortShutdownScript) +FN_GLOBAL_STRING(lp_check_password_script, &Globals.szCheckPasswordScript) + FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook) FN_GLOBAL_STRING(lp_wins_partners, &Globals.szWINSPartners) FN_GLOBAL_STRING(lp_template_primary_group, &Globals.szTemplatePrimaryGroup) diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c index 9af34705df5..454aa8d8702 100644 --- a/source/passdb/pdb_ldap.c +++ b/source/passdb/pdb_ldap.c @@ -148,6 +148,27 @@ static char** get_userattr_list( int schema_ver ) return NULL; } +/************************************************************************** + Return the list of attribute names to delete given a user schema version. +**************************************************************************/ + +static char** get_userattr_delete_list( int schema_ver ) +{ + switch ( schema_ver ) { + case SCHEMAVER_SAMBAACCOUNT: + return get_attr_list( attrib_map_to_delete_v22 ); + + case SCHEMAVER_SAMBASAMACCOUNT: + return get_attr_list( attrib_map_to_delete_v30 ); + default: + DEBUG(0,("get_userattr_list: unknown schema version specified!\n")); + break; + } + + return NULL; +} + + /******************************************************************* Generate the LDAP search filter for the objectclass based on the version of the schema we are using. @@ -299,11 +320,16 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state, really exist. */ for (attrib = attrs; *attrib != NULL; attrib++) { - if ((StrCaseCmp(*attrib, name) == 0) && - !(StrCaseCmp(*attrib, - get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_MOD_TIMESTAMP)))) { - DEBUG(10, ("ldapsam_delete_entry: deleting attribute %s\n", name)); - smbldap_set_mod(&mods, LDAP_MOD_DELETE, name, NULL); + /* Don't delete LDAP_ATTR_MOD_TIMESTAMP attribute. */ + if (strequal(*attrib, get_userattr_key2string(ldap_state->schema_ver, + LDAP_ATTR_MOD_TIMESTAMP))) { + continue; + } + if (strequal(*attrib, name)) { + DEBUG(10, ("ldapsam_delete_entry: deleting " + "attribute %s\n", name)); + smbldap_set_mod(&mods, LDAP_MOD_DELETE, name, + NULL); } } @@ -1229,8 +1255,13 @@ static void append_attr(char ***attr_list, const char *new_attr) { int i; - for (i=0; (*attr_list)[i] != NULL; i++) + if (new_attr == NULL) { + return; + } + + for (i=0; (*attr_list)[i] != NULL; i++) { ; + } (*attr_list) = Realloc((*attr_list), sizeof(**attr_list) * (i+2)); SMB_ASSERT((*attr_list) != NULL); @@ -1515,7 +1546,7 @@ static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_A DEBUG (3, ("ldapsam_delete_sam_account: Deleting user %s from LDAP.\n", sname)); - attr_list= get_userattr_list( ldap_state->schema_ver ); + attr_list= get_userattr_delete_list( ldap_state->schema_ver ); rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list); if (rc != LDAP_SUCCESS) { diff --git a/source/passdb/pdb_smbpasswd.c b/source/passdb/pdb_smbpasswd.c index 6ebac1c01a5..805201615ce 100644 --- a/source/passdb/pdb_smbpasswd.c +++ b/source/passdb/pdb_smbpasswd.c @@ -70,20 +70,21 @@ enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE }; static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth) { - if (fd < 0) - return False; + if (fd < 0) { + return False; + } - if(*plock_depth == 0) { - if (!do_file_lock(fd, secs, type)) { - DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n", - strerror(errno))); - return False; - } - } + if(*plock_depth == 0) { + if (!do_file_lock(fd, secs, type)) { + DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n", + strerror(errno))); + return False; + } + } - (*plock_depth)++; + (*plock_depth)++; - return True; + return True; } /*************************************************************** @@ -92,25 +93,27 @@ static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth) static BOOL pw_file_unlock(int fd, int *plock_depth) { - BOOL ret=True; + BOOL ret=True; - if (fd == 0 || *plock_depth == 0) { - return True; - } + if (fd == 0 || *plock_depth == 0) { + return True; + } - if(*plock_depth == 1) - ret = do_file_lock(fd, 5, F_UNLCK); + if(*plock_depth == 1) { + ret = do_file_lock(fd, 5, F_UNLCK); + } - if (*plock_depth > 0) - (*plock_depth)--; + if (*plock_depth > 0) { + (*plock_depth)--; + } - if(!ret) - DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n", - strerror(errno))); - return ret; + if(!ret) { + DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n", + strerror(errno))); + } + return ret; } - /************************************************************** Intialize a smb_passwd struct *************************************************************/ @@ -133,153 +136,160 @@ static void pdb_init_smb(struct smb_passwd *user) static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth) { - FILE *fp = NULL; - const char *open_mode = NULL; - int race_loop = 0; - int lock_type = F_RDLCK; - - if (!*pfile) { - DEBUG(0, ("startsmbfilepwent: No SMB password file set\n")); - return (NULL); - } - - switch(type) { - case PWF_READ: - open_mode = "rb"; - lock_type = F_RDLCK; - break; - case PWF_UPDATE: - open_mode = "r+b"; - lock_type = F_WRLCK; - break; - case PWF_CREATE: - /* - * Ensure atomic file creation. - */ - { - int i, fd = -1; - - for(i = 0; i < 5; i++) { - if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) - break; - sys_usleep(200); /* Spin, spin... */ - } - if(fd == -1) { - DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile)); - return NULL; - } - close(fd); - open_mode = "r+b"; - lock_type = F_WRLCK; - break; - } - } + FILE *fp = NULL; + const char *open_mode = NULL; + int race_loop = 0; + int lock_type = F_RDLCK; + + if (!*pfile) { + DEBUG(0, ("startsmbfilepwent: No SMB password file set\n")); + return (NULL); + } + + switch(type) { + case PWF_READ: + open_mode = "rb"; + lock_type = F_RDLCK; + break; + case PWF_UPDATE: + open_mode = "r+b"; + lock_type = F_WRLCK; + break; + case PWF_CREATE: + /* + * Ensure atomic file creation. + */ + { + int i, fd = -1; + + for(i = 0; i < 5; i++) { + if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) { + break; + } + sys_usleep(200); /* Spin, spin... */ + } + if(fd == -1) { + DEBUG(0,("startsmbfilepwent_internal: too many race conditions \ +creating file %s\n", pfile)); + return NULL; + } + close(fd); + open_mode = "r+b"; + lock_type = F_WRLCK; + break; + } + } - for(race_loop = 0; race_loop < 5; race_loop++) { - DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile)); + for(race_loop = 0; race_loop < 5; race_loop++) { + DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile)); + + if((fp = sys_fopen(pfile, open_mode)) == NULL) { + + /* + * If smbpasswd file doesn't exist, then create new one. This helps to avoid + * confusing error msg when adding user account first time. + */ + if (errno == ENOENT) { + if ((fp = sys_fopen(pfile, "a+")) != NULL) { + DEBUG(0, ("startsmbfilepwent_internal: file %s did not \ +exist. File successfully created.\n", pfile)); + } else { + DEBUG(0, ("startsmbfilepwent_internal: file %s did not \ +exist. Couldn't create new one. Error was: %s", + pfile, strerror(errno))); + return NULL; + } + } else { + DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. \ +Error was: %s\n", pfile, strerror(errno))); + return NULL; + } + } - if((fp = sys_fopen(pfile, open_mode)) == NULL) { - - /* - * If smbpasswd file doesn't exist, then create new one. This helps to avoid - * confusing error msg when adding user account first time. - */ - if (errno == ENOENT) { - if ((fp = sys_fopen(pfile, "a+")) != NULL) { - DEBUG(0, ("startsmbfilepwent_internal: file %s did not exist. File successfully created.\n", pfile)); - - } else { - DEBUG(0, ("startsmbfilepwent_internal: file %s did not exist. Couldn't create new one. Error was: %s", - pfile, strerror(errno))); - return NULL; - } - - } else { - DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. Error was: %s\n", pfile, strerror(errno))); - return NULL; - } - } - - if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) { - DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) )); - fclose(fp); - return NULL; - } - - /* - * Only check for replacement races on update or create. - * For read we don't mind if the data is one record out of date. - */ - - if(type == PWF_READ) { - break; - } else { - SMB_STRUCT_STAT sbuf1, sbuf2; - - /* - * Avoid the potential race condition between the open and the lock - * by doing a stat on the filename and an fstat on the fd. If the - * two inodes differ then someone did a rename between the open and - * the lock. Back off and try the open again. Only do this 5 times to - * prevent infinate loops. JRA. - */ - - if (sys_stat(pfile,&sbuf1) != 0) { - DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno))); - pw_file_unlock(fileno(fp), lock_depth); - fclose(fp); - return NULL; - } - - if (sys_fstat(fileno(fp),&sbuf2) != 0) { - DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno))); - pw_file_unlock(fileno(fp), lock_depth); - fclose(fp); - return NULL; - } - - if( sbuf1.st_ino == sbuf2.st_ino) { - /* No race. */ - break; - } - - /* - * Race occurred - back off and try again... - */ - - pw_file_unlock(fileno(fp), lock_depth); - fclose(fp); - } - } - - if(race_loop == 5) { - DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile)); - return NULL; - } - - /* Set a buffer to do more efficient reads */ - setvbuf(fp, (char *)NULL, _IOFBF, 1024); - - /* Make sure it is only rw by the owner */ + if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) { + DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. \ +Error was %s\n", pfile, strerror(errno) )); + fclose(fp); + return NULL; + } + + /* + * Only check for replacement races on update or create. + * For read we don't mind if the data is one record out of date. + */ + + if(type == PWF_READ) { + break; + } else { + SMB_STRUCT_STAT sbuf1, sbuf2; + + /* + * Avoid the potential race condition between the open and the lock + * by doing a stat on the filename and an fstat on the fd. If the + * two inodes differ then someone did a rename between the open and + * the lock. Back off and try the open again. Only do this 5 times to + * prevent infinate loops. JRA. + */ + + if (sys_stat(pfile,&sbuf1) != 0) { + DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. \ +Error was %s\n", pfile, strerror(errno))); + pw_file_unlock(fileno(fp), lock_depth); + fclose(fp); + return NULL; + } + + if (sys_fstat(fileno(fp),&sbuf2) != 0) { + DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. \ +Error was %s\n", pfile, strerror(errno))); + pw_file_unlock(fileno(fp), lock_depth); + fclose(fp); + return NULL; + } + + if( sbuf1.st_ino == sbuf2.st_ino) { + /* No race. */ + break; + } + + /* + * Race occurred - back off and try again... + */ + + pw_file_unlock(fileno(fp), lock_depth); + fclose(fp); + } + } + + if(race_loop == 5) { + DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile)); + return NULL; + } + + /* Set a buffer to do more efficient reads */ + setvbuf(fp, (char *)NULL, _IOFBF, 1024); + + /* Make sure it is only rw by the owner */ #ifdef HAVE_FCHMOD - if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) { + if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) { #else - if(chmod(pfile, S_IRUSR|S_IWUSR) == -1) { + if(chmod(pfile, S_IRUSR|S_IWUSR) == -1) { #endif - DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \ + DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \ Error was %s\n.", pfile, strerror(errno) )); - pw_file_unlock(fileno(fp), lock_depth); - fclose(fp); - return NULL; - } + pw_file_unlock(fileno(fp), lock_depth); + fclose(fp); + return NULL; + } - /* We have a lock on the file. */ - return fp; + /* We have a lock on the file. */ + return fp; } /*************************************************************** End enumeration of the smbpasswd list. ****************************************************************/ + static void endsmbfilepwent(FILE *fp, int *lock_depth) { if (!fp) { @@ -297,225 +307,235 @@ static void endsmbfilepwent(FILE *fp, int *lock_depth) static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp) { - /* Static buffers we will return. */ - struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf; - char *user_name = smbpasswd_state->user_name; - unsigned char *smbpwd = smbpasswd_state->smbpwd; - unsigned char *smbntpwd = smbpasswd_state->smbntpwd; - char linebuf[256]; - unsigned char c; - unsigned char *p; - long uidval; - size_t linebuf_len; - - if(fp == NULL) { - DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n")); - return NULL; - } - - pdb_init_smb(pw_buf); - - pw_buf->acct_ctrl = ACB_NORMAL; - - /* - * Scan the file, a line at a time and check if the name matches. - */ - while (!feof(fp)) { - linebuf[0] = '\0'; - - fgets(linebuf, 256, fp); - if (ferror(fp)) { - return NULL; - } - - /* - * Check if the string is terminated with a newline - if not - * then we must keep reading and discard until we get one. - */ - if ((linebuf_len = strlen(linebuf)) == 0) - continue; - - if (linebuf[linebuf_len - 1] != '\n') { - c = '\0'; - while (!ferror(fp) && !feof(fp)) { - c = fgetc(fp); - if (c == '\n') - break; - } - } else - linebuf[linebuf_len - 1] = '\0'; + /* Static buffers we will return. */ + struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf; + char *user_name = smbpasswd_state->user_name; + unsigned char *smbpwd = smbpasswd_state->smbpwd; + unsigned char *smbntpwd = smbpasswd_state->smbntpwd; + char linebuf[256]; + unsigned char c; + unsigned char *p; + long uidval; + size_t linebuf_len; + + if(fp == NULL) { + DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n")); + return NULL; + } + + pdb_init_smb(pw_buf); + pw_buf->acct_ctrl = ACB_NORMAL; + + /* + * Scan the file, a line at a time and check if the name matches. + */ + while (!feof(fp)) { + linebuf[0] = '\0'; + + fgets(linebuf, 256, fp); + if (ferror(fp)) { + return NULL; + } + + /* + * Check if the string is terminated with a newline - if not + * then we must keep reading and discard until we get one. + */ + if ((linebuf_len = strlen(linebuf)) == 0) { + continue; + } + + if (linebuf[linebuf_len - 1] != '\n') { + c = '\0'; + while (!ferror(fp) && !feof(fp)) { + c = fgetc(fp); + if (c == '\n') { + break; + } + } + } else { + linebuf[linebuf_len - 1] = '\0'; + } #ifdef DEBUG_PASSWORD - DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf)); + DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf)); #endif - if ((linebuf[0] == 0) && feof(fp)) { - DEBUG(4, ("getsmbfilepwent: end of file reached\n")); - break; - } - /* - * The line we have should be of the form :- - * - * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently - * ignored.... - * - * or, - * - * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored.... - * - * if Windows NT compatible passwords are also present. - * [Account type] is an ascii encoding of the type of account. - * LCT-(8 hex digits) is the time_t value of the last change time. - */ - - if (linebuf[0] == '#' || linebuf[0] == '\0') { - DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n")); - continue; - } - p = (unsigned char *) strchr_m(linebuf, ':'); - if (p == NULL) { - DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n")); - continue; - } - /* - * As 256 is shorter than a pstring we don't need to check - * length here - if this ever changes.... - */ - SMB_ASSERT(sizeof(pstring) > sizeof(linebuf)); - - strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); - user_name[PTR_DIFF(p, linebuf)] = '\0'; - - /* Get smb uid. */ - - p++; /* Go past ':' */ - - if(*p == '-') { - DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n")); - continue; - } - - if (!isdigit(*p)) { - DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n")); - continue; - } - - uidval = atoi((char *) p); - - while (*p && isdigit(*p)) - p++; - - if (*p != ':') { - DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n")); - continue; - } - - pw_buf->smb_name = user_name; - pw_buf->smb_userid = uidval; - - /* - * Now get the password value - this should be 32 hex digits - * which are the ascii representations of a 16 byte string. - * Get two at a time and put them into the password. - */ - - /* Skip the ':' */ - p++; - - if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { - DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n")); - continue; - } - - if (p[32] != ':') { - DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n")); - continue; - } - - if (strnequal((char *) p, "NO PASSWORD", 11)) { - pw_buf->smb_passwd = NULL; - pw_buf->acct_ctrl |= ACB_PWNOTREQ; - } else { - if (*p == '*' || *p == 'X') { - /* NULL LM password */ - pw_buf->smb_passwd = NULL; - DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name)); - } else if (pdb_gethexpwd((char *)p, smbpwd)) { - pw_buf->smb_passwd = smbpwd; - } else { - pw_buf->smb_passwd = NULL; - DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n")); - } - } - - /* - * Now check if the NT compatible password is - * available. - */ - pw_buf->smb_nt_passwd = NULL; - - p += 33; /* Move to the first character of the line after - the lanman password. */ - if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) { - if (*p != '*' && *p != 'X') { - if(pdb_gethexpwd((char *)p,smbntpwd)) - pw_buf->smb_nt_passwd = smbntpwd; - } - p += 33; /* Move to the first character of the line after - the NT password. */ - } - - DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n", - user_name, uidval)); - - if (*p == '[') - { - unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']'); - pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p); - - /* Must have some account type set. */ - if(pw_buf->acct_ctrl == 0) - pw_buf->acct_ctrl = ACB_NORMAL; - - /* Now try and get the last change time. */ - if(end_p) - p = end_p + 1; - if(*p == ':') { - p++; - if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) { - int i; - p += 4; - for(i = 0; i < 8; i++) { - if(p[i] == '\0' || !isxdigit(p[i])) - break; - } - if(i == 8) { - /* - * p points at 8 characters of hex digits - - * read into a time_t as the seconds since - * 1970 that the password was last changed. - */ - pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16); - } - } - } - } else { - /* 'Old' style file. Fake up based on user name. */ - /* - * Currently trust accounts are kept in the same - * password file as 'normal accounts'. If this changes - * we will have to fix this code. JRA. - */ - if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') { - pw_buf->acct_ctrl &= ~ACB_NORMAL; - pw_buf->acct_ctrl |= ACB_WSTRUST; - } - } - - return pw_buf; - } - - DEBUG(5,("getsmbfilepwent: end of file reached.\n")); - return NULL; + if ((linebuf[0] == 0) && feof(fp)) { + DEBUG(4, ("getsmbfilepwent: end of file reached\n")); + break; + } + + /* + * The line we have should be of the form :- + * + * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently + * ignored.... + * + * or, + * + * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored.... + * + * if Windows NT compatible passwords are also present. + * [Account type] is an ascii encoding of the type of account. + * LCT-(8 hex digits) is the time_t value of the last change time. + */ + + if (linebuf[0] == '#' || linebuf[0] == '\0') { + DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n")); + continue; + } + p = (unsigned char *) strchr_m(linebuf, ':'); + if (p == NULL) { + DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n")); + continue; + } + + /* + * As 256 is shorter than a pstring we don't need to check + * length here - if this ever changes.... + */ + SMB_ASSERT(sizeof(pstring) > sizeof(linebuf)); + + strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); + user_name[PTR_DIFF(p, linebuf)] = '\0'; + + /* Get smb uid. */ + + p++; /* Go past ':' */ + + if(*p == '-') { + DEBUG(0, ("getsmbfilepwent: user name %s has a negative uid.\n", user_name)); + continue; + } + + if (!isdigit(*p)) { + DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (uid not number)\n", + user_name)); + continue; + } + + uidval = atoi((char *) p); + + while (*p && isdigit(*p)) { + p++; + } + + if (*p != ':') { + DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no : after uid)\n", + user_name)); + continue; + } + + pw_buf->smb_name = user_name; + pw_buf->smb_userid = uidval; + + /* + * Now get the password value - this should be 32 hex digits + * which are the ascii representations of a 16 byte string. + * Get two at a time and put them into the password. + */ + + /* Skip the ':' */ + p++; + + if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { + DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (passwd too short)\n", + user_name )); + continue; + } + + if (p[32] != ':') { + DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no terminating :)\n", + user_name)); + continue; + } + + if (strnequal((char *) p, "NO PASSWORD", 11)) { + pw_buf->smb_passwd = NULL; + pw_buf->acct_ctrl |= ACB_PWNOTREQ; + } else { + if (*p == '*' || *p == 'X') { + /* NULL LM password */ + pw_buf->smb_passwd = NULL; + DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name)); + } else if (pdb_gethexpwd((char *)p, smbpwd)) { + pw_buf->smb_passwd = smbpwd; + } else { + pw_buf->smb_passwd = NULL; + DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry for user %s \ +(non hex chars)\n", user_name)); + } + } + + /* + * Now check if the NT compatible password is + * available. + */ + pw_buf->smb_nt_passwd = NULL; + p += 33; /* Move to the first character of the line after the lanman password. */ + if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) { + if (*p != '*' && *p != 'X') { + if(pdb_gethexpwd((char *)p,smbntpwd)) { + pw_buf->smb_nt_passwd = smbntpwd; + } + } + p += 33; /* Move to the first character of the line after the NT password. */ + } + + DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n", + user_name, uidval)); + + if (*p == '[') { + unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']'); + pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p); + + /* Must have some account type set. */ + if(pw_buf->acct_ctrl == 0) { + pw_buf->acct_ctrl = ACB_NORMAL; + } + + /* Now try and get the last change time. */ + if(end_p) { + p = end_p + 1; + } + if(*p == ':') { + p++; + if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) { + int i; + p += 4; + for(i = 0; i < 8; i++) { + if(p[i] == '\0' || !isxdigit(p[i])) { + break; + } + } + if(i == 8) { + /* + * p points at 8 characters of hex digits - + * read into a time_t as the seconds since + * 1970 that the password was last changed. + */ + pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16); + } + } + } + } else { + /* 'Old' style file. Fake up based on user name. */ + /* + * Currently trust accounts are kept in the same + * password file as 'normal accounts'. If this changes + * we will have to fix this code. JRA. + */ + if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') { + pw_buf->acct_ctrl &= ~ACB_NORMAL; + pw_buf->acct_ctrl |= ACB_WSTRUST; + } + } + + return pw_buf; + } + + DEBUG(5,("getsmbfilepwent: end of file reached.\n")); + return NULL; } /************************************************************************ @@ -524,35 +544,38 @@ static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_s static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd) { - int new_entry_length; - char *new_entry; - char *p; - - new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2; + int new_entry_length; + char *new_entry; + char *p; - if((new_entry = (char *)malloc( new_entry_length )) == NULL) { - DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name )); - return NULL; - } + new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2; - slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid); - - p = new_entry+strlen(new_entry); - - pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl); + if((new_entry = (char *)malloc( new_entry_length )) == NULL) { + DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", + newpwd->smb_name )); + return NULL; + } - p+=strlen(p); *p = ':'; p++; + slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid); - pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl); + p = new_entry+strlen(new_entry); + pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl); + p+=strlen(p); + *p = ':'; + p++; - p+=strlen(p); *p = ':'; p++; + pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl); + p+=strlen(p); + *p = ':'; + p++; - /* Add the account encoding and the last change time. */ - slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n", - pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN), - (uint32)newpwd->pass_last_set_time); + /* Add the account encoding and the last change time. */ + slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n", + pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN), + (uint32)newpwd->pass_last_set_time); - return new_entry; + return new_entry; } /************************************************************************ @@ -561,101 +584,95 @@ static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd) static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, struct smb_passwd *newpwd) { - const char *pfile = smbpasswd_state->smbpasswd_file; - struct smb_passwd *pwd = NULL; - FILE *fp = NULL; - int wr_len; - int fd; - size_t new_entry_length; - char *new_entry; - SMB_OFF_T offpos; - uint32 max_found_uid = 0; + const char *pfile = smbpasswd_state->smbpasswd_file; + struct smb_passwd *pwd = NULL; + FILE *fp = NULL; + int wr_len; + int fd; + size_t new_entry_length; + char *new_entry; + SMB_OFF_T offpos; + uint32 max_found_uid = 0; - /* Open the smbpassword file - for update. */ - fp = startsmbfilepwent(pfile, PWF_UPDATE, &(smbpasswd_state->pw_file_lock_depth)); - - if (fp == NULL && errno == ENOENT) { - /* Try again - create. */ - fp = startsmbfilepwent(pfile, PWF_CREATE, &(smbpasswd_state->pw_file_lock_depth)); - } - - if (fp == NULL) { - DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n")); - return False; - } - - /* - * Scan the file, a line at a time and check if the name matches. - */ - - while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) - { - if (strequal(newpwd->smb_name, pwd->smb_name)) - { - DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name)); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - return False; - } + /* Open the smbpassword file - for update. */ + fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth); + + if (fp == NULL && errno == ENOENT) { + /* Try again - create. */ + fp = startsmbfilepwent(pfile, PWF_CREATE, &smbpasswd_state->pw_file_lock_depth); + } + + if (fp == NULL) { + DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n")); + return False; + } + + /* + * Scan the file, a line at a time and check if the name matches. + */ + + while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) { + if (strequal(newpwd->smb_name, pwd->smb_name)) { + DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name)); + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + return False; + } - /* Look for a free uid for use in non-unix accounts */ - if (pwd->smb_userid > max_found_uid) { - max_found_uid = pwd->smb_userid; - } - } - - /* Ok - entry doesn't exist. We can add it */ - - /* Create a new smb passwd entry and set it to the given password. */ - /* - * The add user write needs to be atomic - so get the fd from - * the fp and do a raw write() call. - */ - fd = fileno(fp); - - if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1) - { - DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \ + /* Look for a free uid for use in non-unix accounts */ + if (pwd->smb_userid > max_found_uid) { + max_found_uid = pwd->smb_userid; + } + } + + /* Ok - entry doesn't exist. We can add it */ + + /* Create a new smb passwd entry and set it to the given password. */ + /* + * The add user write needs to be atomic - so get the fd from + * the fp and do a raw write() call. + */ + fd = fileno(fp); + + if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1) { + DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \ Error was %s\n", newpwd->smb_name, pfile, strerror(errno))); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - return False; - } + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + return False; + } - if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) - { - DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \ + if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) { + DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \ Error was %s\n", newpwd->smb_name, pfile, strerror(errno))); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - return False; - } + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + return False; + } - new_entry_length = strlen(new_entry); + new_entry_length = strlen(new_entry); #ifdef DEBUG_PASSWORD - DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", - fd, new_entry_length, new_entry)); + DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", + fd, new_entry_length, new_entry)); #endif - if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) - { - DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \ + if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) { + DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \ Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno))); - /* Remove the entry we just wrote. */ - if(sys_ftruncate(fd, offpos) == -1) - { - DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \ + /* Remove the entry we just wrote. */ + if(sys_ftruncate(fd, offpos) == -1) { + DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \ Error was %s. Password file may be corrupt ! Please examine by hand !\n", - newpwd->smb_name, strerror(errno))); - } + newpwd->smb_name, strerror(errno))); + } - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - free(new_entry); - return False; - } + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + free(new_entry); + return False; + } - free(new_entry); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - return True; + free(new_entry); + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + return True; } /************************************************************************ @@ -669,350 +686,356 @@ Error was %s. Password file may be corrupt ! Please examine by hand !\n", static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd) { - /* Static buffers we will return. */ + /* Static buffers we will return. */ pstring user_name; - char linebuf[256]; - char readbuf[1024]; - unsigned char c; - fstring ascii_p16; - fstring encode_bits; - unsigned char *p = NULL; - size_t linebuf_len = 0; - FILE *fp; - int lockfd; - const char *pfile = smbpasswd_state->smbpasswd_file; - BOOL found_entry = False; - BOOL got_pass_last_set_time = False; - - SMB_OFF_T pwd_seekpos = 0; - - int i; - int wr_len; - int fd; - - if (!*pfile) { - DEBUG(0, ("No SMB password file set\n")); - return False; - } - DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile)); - - fp = sys_fopen(pfile, "r+"); - - if (fp == NULL) { - DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile)); - return False; - } - /* Set a buffer to do more efficient reads */ - setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf)); - - lockfd = fileno(fp); - - if (!pw_file_lock(lockfd, F_WRLCK, 5, &(smbpasswd_state->pw_file_lock_depth))) { - DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile)); - fclose(fp); - return False; - } - - /* Make sure it is only rw by the owner */ - chmod(pfile, 0600); - - /* We have a write lock on the file. */ - /* - * Scan the file, a line at a time and check if the name matches. - */ - while (!feof(fp)) { - pwd_seekpos = sys_ftell(fp); - - linebuf[0] = '\0'; - - fgets(linebuf, sizeof(linebuf), fp); - if (ferror(fp)) { - pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - /* - * Check if the string is terminated with a newline - if not - * then we must keep reading and discard until we get one. - */ - linebuf_len = strlen(linebuf); - if (linebuf[linebuf_len - 1] != '\n') { - c = '\0'; - while (!ferror(fp) && !feof(fp)) { - c = fgetc(fp); - if (c == '\n') { - break; - } - } - } else { - linebuf[linebuf_len - 1] = '\0'; - } + char linebuf[256]; + char readbuf[1024]; + unsigned char c; + fstring ascii_p16; + fstring encode_bits; + unsigned char *p = NULL; + size_t linebuf_len = 0; + FILE *fp; + int lockfd; + const char *pfile = smbpasswd_state->smbpasswd_file; + BOOL found_entry = False; + BOOL got_pass_last_set_time = False; + + SMB_OFF_T pwd_seekpos = 0; + + int i; + int wr_len; + int fd; + + if (!*pfile) { + DEBUG(0, ("No SMB password file set\n")); + return False; + } + DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile)); + + fp = sys_fopen(pfile, "r+"); + + if (fp == NULL) { + DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile)); + return False; + } + /* Set a buffer to do more efficient reads */ + setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf)); + + lockfd = fileno(fp); + + if (!pw_file_lock(lockfd, F_WRLCK, 5, &smbpasswd_state->pw_file_lock_depth)) { + DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile)); + fclose(fp); + return False; + } + + /* Make sure it is only rw by the owner */ + chmod(pfile, 0600); + + /* We have a write lock on the file. */ + /* + * Scan the file, a line at a time and check if the name matches. + */ + while (!feof(fp)) { + pwd_seekpos = sys_ftell(fp); + + linebuf[0] = '\0'; + + fgets(linebuf, sizeof(linebuf), fp); + if (ferror(fp)) { + pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + /* + * Check if the string is terminated with a newline - if not + * then we must keep reading and discard until we get one. + */ + linebuf_len = strlen(linebuf); + if (linebuf[linebuf_len - 1] != '\n') { + c = '\0'; + while (!ferror(fp) && !feof(fp)) { + c = fgetc(fp); + if (c == '\n') { + break; + } + } + } else { + linebuf[linebuf_len - 1] = '\0'; + } #ifdef DEBUG_PASSWORD - DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf)); + DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf)); #endif - if ((linebuf[0] == 0) && feof(fp)) { - DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n")); - break; - } - - /* - * The line we have should be of the form :- - * - * username:uid:[32hex bytes]:....other flags presently - * ignored.... - * - * or, - * - * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored. - * - * if Windows NT compatible passwords are also present. - */ - - if (linebuf[0] == '#' || linebuf[0] == '\0') { - DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n")); - continue; - } - - p = (unsigned char *) strchr_m(linebuf, ':'); - - if (p == NULL) { - DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n")); - continue; - } - - /* - * As 256 is shorter than a pstring we don't need to check - * length here - if this ever changes.... - */ - - SMB_ASSERT(sizeof(user_name) > sizeof(linebuf)); - - strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); - user_name[PTR_DIFF(p, linebuf)] = '\0'; - if (strequal(user_name, pwd->smb_name)) { - found_entry = True; - break; - } - } - - if (!found_entry) { - pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - - DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n", - pwd->smb_name)); - return False; - } - - DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n")); - - /* User name matches - get uid and password */ - p++; /* Go past ':' */ - - if (!isdigit(*p)) { - DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n")); - pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - while (*p && isdigit(*p)) - p++; - if (*p != ':') { - DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n")); - pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - /* - * Now get the password value - this should be 32 hex digits - * which are the ascii representations of a 16 byte string. - * Get two at a time and put them into the password. - */ - p++; - - /* Record exact password position */ - pwd_seekpos += PTR_DIFF(p, linebuf); - - if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { - DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n")); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return (False); - } - - if (p[32] != ':') { - DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n")); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - /* Now check if the NT compatible password is - available. */ - p += 33; /* Move to the first character of the line after - the lanman password. */ - if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { - DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n")); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return (False); - } - - if (p[32] != ':') { - DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n")); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - /* - * Now check if the account info and the password last - * change time is available. - */ - p += 33; /* Move to the first character of the line after - the NT password. */ - - if (*p == '[') { - - i = 0; - encode_bits[i++] = *p++; - while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']')) - encode_bits[i++] = *p++; - - encode_bits[i++] = ']'; - encode_bits[i++] = '\0'; - - if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) { - /* - * We are using a new format, space padded - * acct ctrl field. Encode the given acct ctrl - * bits into it. - */ - fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN)); - } else { - DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format. This is no longer supported.!\n")); - DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n")); - return False; - } - - /* Go past the ']' */ - if(linebuf_len > PTR_DIFF(p, linebuf)) - p++; - - if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) { - p++; - - /* We should be pointing at the LCT entry. */ - if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) { - - p += 4; - for(i = 0; i < 8; i++) { - if(p[i] == '\0' || !isxdigit(p[i])) - break; - } - if(i == 8) { - /* - * p points at 8 characters of hex digits - - * read into a time_t as the seconds since - * 1970 that the password was last changed. - */ - got_pass_last_set_time = True; - } /* i == 8 */ - } /* *p && StrnCaseCmp() */ - } /* p == ':' */ - } /* p == '[' */ - - /* Entry is correctly formed. */ - - /* Create the 32 byte representation of the new p16 */ - pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl); - - /* Add on the NT md4 hash */ - ascii_p16[32] = ':'; - wr_len = 66; - pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl); - ascii_p16[65] = ':'; - ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */ - - /* Add on the account info bits and the time of last - password change. */ - - if(got_pass_last_set_time) { - slprintf(&ascii_p16[strlen(ascii_p16)], - sizeof(ascii_p16)-(strlen(ascii_p16)+1), - "%s:LCT-%08X:", - encode_bits, (uint32)pwd->pass_last_set_time ); - wr_len = strlen(ascii_p16); - } + if ((linebuf[0] == 0) && feof(fp)) { + DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n")); + break; + } + + /* + * The line we have should be of the form :- + * + * username:uid:[32hex bytes]:....other flags presently + * ignored.... + * + * or, + * + * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored. + * + * if Windows NT compatible passwords are also present. + */ + + if (linebuf[0] == '#' || linebuf[0] == '\0') { + DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n")); + continue; + } + + p = (unsigned char *) strchr_m(linebuf, ':'); + + if (p == NULL) { + DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n")); + continue; + } + + /* + * As 256 is shorter than a pstring we don't need to check + * length here - if this ever changes.... + */ + + SMB_ASSERT(sizeof(user_name) > sizeof(linebuf)); + + strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); + user_name[PTR_DIFF(p, linebuf)] = '\0'; + if (strequal(user_name, pwd->smb_name)) { + found_entry = True; + break; + } + } + + if (!found_entry) { + pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); + fclose(fp); + + DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n", + pwd->smb_name)); + return False; + } + + DEBUG(6, ("mod_smbfilepwd_entry: entry exists for user %s\n", pwd->smb_name)); + + /* User name matches - get uid and password */ + p++; /* Go past ':' */ + + if (!isdigit(*p)) { + DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (uid not number)\n", + pwd->smb_name)); + pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + while (*p && isdigit(*p)) { + p++; + } + if (*p != ':') { + DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no : after uid)\n", + pwd->smb_name)); + pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + /* + * Now get the password value - this should be 32 hex digits + * which are the ascii representations of a 16 byte string. + * Get two at a time and put them into the password. + */ + p++; + + /* Record exact password position */ + pwd_seekpos += PTR_DIFF(p, linebuf); + + if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { + DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n", + pwd->smb_name)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return (False); + } + + if (p[32] != ':') { + DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n", + pwd->smb_name)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + /* Now check if the NT compatible password is available. */ + p += 33; /* Move to the first character of the line after the lanman password. */ + if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { + DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n", + pwd->smb_name)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return (False); + } + + if (p[32] != ':') { + DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n", + pwd->smb_name)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + /* + * Now check if the account info and the password last + * change time is available. + */ + p += 33; /* Move to the first character of the line after the NT password. */ + + if (*p == '[') { + i = 0; + encode_bits[i++] = *p++; + while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']')) { + encode_bits[i++] = *p++; + } + + encode_bits[i++] = ']'; + encode_bits[i++] = '\0'; + + if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) { + /* + * We are using a new format, space padded + * acct ctrl field. Encode the given acct ctrl + * bits into it. + */ + fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN)); + } else { + DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format for user %s. \ +This is no longer supported.!\n", pwd->smb_name)); + DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n")); + pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + /* Go past the ']' */ + if(linebuf_len > PTR_DIFF(p, linebuf)) { + p++; + } + + if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) { + p++; + + /* We should be pointing at the LCT entry. */ + if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) { + p += 4; + for(i = 0; i < 8; i++) { + if(p[i] == '\0' || !isxdigit(p[i])) { + break; + } + } + if(i == 8) { + /* + * p points at 8 characters of hex digits - + * read into a time_t as the seconds since + * 1970 that the password was last changed. + */ + got_pass_last_set_time = True; + } /* i == 8 */ + } /* *p && StrnCaseCmp() */ + } /* p == ':' */ + } /* p == '[' */ + + /* Entry is correctly formed. */ + + /* Create the 32 byte representation of the new p16 */ + pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl); + + /* Add on the NT md4 hash */ + ascii_p16[32] = ':'; + wr_len = 66; + pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl); + ascii_p16[65] = ':'; + ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */ + + /* Add on the account info bits and the time of last password change. */ + if(got_pass_last_set_time) { + slprintf(&ascii_p16[strlen(ascii_p16)], + sizeof(ascii_p16)-(strlen(ascii_p16)+1), + "%s:LCT-%08X:", + encode_bits, (uint32)pwd->pass_last_set_time ); + wr_len = strlen(ascii_p16); + } #ifdef DEBUG_PASSWORD - DEBUG(100,("mod_smbfilepwd_entry: ")); - dump_data(100, ascii_p16, wr_len); + DEBUG(100,("mod_smbfilepwd_entry: ")); + dump_data(100, ascii_p16, wr_len); #endif - if(wr_len > sizeof(linebuf)) { - DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1)); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return (False); - } - - /* - * Do an atomic write into the file at the position defined by - * seekpos. - */ - - /* The mod user write needs to be atomic - so get the fd from - the fp and do a raw write() call. - */ - - fd = fileno(fp); - - if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) { - DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile)); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - /* Sanity check - ensure the areas we are writing are framed by ':' */ - if (read(fd, linebuf, wr_len+1) != wr_len+1) { - DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile)); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) { - DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile)); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } + if(wr_len > sizeof(linebuf)) { + DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return (False); + } + + /* + * Do an atomic write into the file at the position defined by + * seekpos. + */ + + /* The mod user write needs to be atomic - so get the fd from + the fp and do a raw write() call. + */ + + fd = fileno(fp); + + if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) { + DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + /* Sanity check - ensure the areas we are writing are framed by ':' */ + if (read(fd, linebuf, wr_len+1) != wr_len+1) { + DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) { + DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } - if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) { - DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile)); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - if (write(fd, ascii_p16, wr_len) != wr_len) { - DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile)); - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return False; - } - - pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth)); - fclose(fp); - return True; + if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) { + DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + if (write(fd, ascii_p16, wr_len) != wr_len) { + DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile)); + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return False; + } + + pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); + fclose(fp); + return True; } /************************************************************************ @@ -1022,100 +1045,97 @@ static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, con static BOOL del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name) { const char *pfile = smbpasswd_state->smbpasswd_file; - pstring pfile2; - struct smb_passwd *pwd = NULL; - FILE *fp = NULL; - FILE *fp_write = NULL; - int pfile2_lockdepth = 0; - - slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() ); - - /* - * Open the smbpassword file - for update. It needs to be update - * as we need any other processes to wait until we have replaced - * it. - */ - - if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &(smbpasswd_state->pw_file_lock_depth))) == NULL) { - DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile)); - return False; - } - - /* - * Create the replacement password file. - */ - if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) { - DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile)); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - return False; - } - - /* - * Scan the file, a line at a time and check if the name matches. - */ - - while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) { - char *new_entry; - size_t new_entry_length; - - if (strequal(name, pwd->smb_name)) { - DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name)); - continue; - } - - /* - * We need to copy the entry out into the second file. - */ - - if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) - { - DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \ + pstring pfile2; + struct smb_passwd *pwd = NULL; + FILE *fp = NULL; + FILE *fp_write = NULL; + int pfile2_lockdepth = 0; + + slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() ); + + /* + * Open the smbpassword file - for update. It needs to be update + * as we need any other processes to wait until we have replaced + * it. + */ + + if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth)) == NULL) { + DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile)); + return False; + } + + /* + * Create the replacement password file. + */ + if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) { + DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile)); + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + return False; + } + + /* + * Scan the file, a line at a time and check if the name matches. + */ + + while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) { + char *new_entry; + size_t new_entry_length; + + if (strequal(name, pwd->smb_name)) { + DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name)); + continue; + } + + /* + * We need to copy the entry out into the second file. + */ + + if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) { + DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \ Error was %s\n", pwd->smb_name, pfile2, strerror(errno))); - unlink(pfile2); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - endsmbfilepwent(fp_write, &pfile2_lockdepth); - return False; - } + unlink(pfile2); + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + endsmbfilepwent(fp_write, &pfile2_lockdepth); + return False; + } - new_entry_length = strlen(new_entry); + new_entry_length = strlen(new_entry); - if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) - { - DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \ + if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) { + DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \ Error was %s\n", pwd->smb_name, pfile2, strerror(errno))); - unlink(pfile2); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - endsmbfilepwent(fp_write, &pfile2_lockdepth); - free(new_entry); - return False; - } + unlink(pfile2); + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + endsmbfilepwent(fp_write, &pfile2_lockdepth); + free(new_entry); + return False; + } - free(new_entry); - } + free(new_entry); + } - /* - * Ensure pfile2 is flushed before rename. - */ + /* + * Ensure pfile2 is flushed before rename. + */ - if(fflush(fp_write) != 0) - { - DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno))); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - endsmbfilepwent(fp_write,&pfile2_lockdepth); - return False; - } + if(fflush(fp_write) != 0) { + DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno))); + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + endsmbfilepwent(fp_write,&pfile2_lockdepth); + return False; + } - /* - * Do an atomic rename - then release the locks. - */ + /* + * Do an atomic rename - then release the locks. + */ - if(rename(pfile2,pfile) != 0) { - unlink(pfile2); - } + if(rename(pfile2,pfile) != 0) { + unlink(pfile2); + } - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - endsmbfilepwent(fp_write,&pfile2_lockdepth); - return True; + endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); + endsmbfilepwent(fp_write,&pfile2_lockdepth); + return True; } /********************************************************************* @@ -1123,6 +1143,7 @@ Error was %s\n", pwd->smb_name, pfile2, strerror(errno))); We will not allocate any new memory. The smb_passwd struct should only stay around as long as the SAM_ACCOUNT does. ********************************************************************/ + static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass) { uint32 rid; @@ -1166,6 +1187,7 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas /********************************************************************* Create a SAM_ACCOUNT from a smb_passwd struct ********************************************************************/ + static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf) { @@ -1203,6 +1225,7 @@ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, /***************************************************************** Functions to be implemented by the new passdb API ****************************************************************/ + static NTSTATUS smbpasswd_setsampwent (struct pdb_methods *my_methods, BOOL update) { struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; @@ -1212,15 +1235,13 @@ static NTSTATUS smbpasswd_setsampwent (struct pdb_methods *my_methods, BOOL upda &(smbpasswd_state->pw_file_lock_depth)); /* did we fail? Should we try to create it? */ - if (!smbpasswd_state->pw_file && update && errno == ENOENT) - { + if (!smbpasswd_state->pw_file && update && errno == ENOENT) { FILE *fp; /* slprintf(msg_str,msg_str_len-1, "smbpasswd file did not exist - attempting to create it.\n"); */ DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n")); fp = sys_fopen(smbpasswd_state->smbpasswd_file, "w"); - if (fp) - { + if (fp) { fprintf(fp, "# Samba SMB password file\n"); fclose(fp); } @@ -1244,6 +1265,7 @@ static void smbpasswd_endsampwent (struct pdb_methods *my_methods) /***************************************************************** ****************************************************************/ + static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; @@ -1260,8 +1282,7 @@ static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUN return nt_status; } - while (!done) - { + while (!done) { /* do we have an entry? */ pw_buf = getsmbfilepwent(smbpasswd_state, smbpasswd_state->pw_file); if (pw_buf == NULL) @@ -1280,12 +1301,12 @@ static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUN return NT_STATUS_OK; } - /**************************************************************** Search smbpasswd file by iterating over the entries. Do not call getpwnam() for unix account information until we have found the correct entry ***************************************************************/ + static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_acct, const char *username) { diff --git a/source/passdb/pdb_xml.c b/source/passdb/pdb_xml.c index 64cb73ba5a4..6eff57d365e 100644 --- a/source/passdb/pdb_xml.c +++ b/source/passdb/pdb_xml.c @@ -40,6 +40,27 @@ static int xmlsam_debug_level = DBGC_ALL; #undef DBGC_CLASS #define DBGC_CLASS xmlsam_debug_level + +/* Helper utilities for charset conversion */ +static xmlNodePtr smbXmlNewChild(xmlNodePtr prnt, xmlNsPtr ns, const xmlChar *name, const char *content) +{ + char *string_utf8; + xmlNodePtr ret; + + if(!content) return xmlNewChild(prnt, ns, name, NULL); + + + if(push_utf8_allocate(&string_utf8,content) == (size_t)-1) + return NULL; + + ret = xmlNewTextChild(prnt, ns, name, string_utf8); + + SAFE_FREE(string_utf8); + + return ret; +} + + static char * iota(int a) { static char tmp[10]; @@ -394,72 +415,72 @@ static NTSTATUS xmlsam_add_sam_account(struct pdb_methods *methods, SAM_ACCOUNT root = xmlNewDocNode(data->doc, NULL, "samba", NULL); cur = xmlDocSetRootElement(data->doc, root); data->ns = xmlNewNs(root, XML_URL, "samba"); - data->users = xmlNewChild(root, data->ns, "users", NULL); + data->users = smbXmlNewChild(root, data->ns, "users", NULL); } - user = xmlNewChild(data->users, data->ns, "user", NULL); + user = smbXmlNewChild(data->users, data->ns, "user", NULL); xmlNewProp(user, "sid", sid_to_string(sid_str, pdb_get_user_sid(u))); if (pdb_get_username(u) && strcmp(pdb_get_username(u), "")) xmlNewProp(user, "name", pdb_get_username(u)); - cur = xmlNewChild(user, data->ns, "group", NULL); + cur = smbXmlNewChild(user, data->ns, "group", NULL); xmlNewProp(cur, "sid", sid_to_string(sid_str, pdb_get_group_sid(u))); if (pdb_get_init_flags(u, PDB_LOGONTIME) != PDB_DEFAULT) - xmlNewChild(user, data->ns, "logon_time", + smbXmlNewChild(user, data->ns, "logon_time", iota(pdb_get_logon_time(u))); if (pdb_get_init_flags(u, PDB_LOGOFFTIME) != PDB_DEFAULT) - xmlNewChild(user, data->ns, "logoff_time", + smbXmlNewChild(user, data->ns, "logoff_time", iota(pdb_get_logoff_time(u))); if (pdb_get_init_flags(u, PDB_KICKOFFTIME) != PDB_DEFAULT) - xmlNewChild(user, data->ns, "kickoff_time", + smbXmlNewChild(user, data->ns, "kickoff_time", iota(pdb_get_kickoff_time(u))); if (pdb_get_domain(u) && strcmp(pdb_get_domain(u), "")) - xmlNewChild(user, data->ns, "domain", pdb_get_domain(u)); + smbXmlNewChild(user, data->ns, "domain", pdb_get_domain(u)); if (pdb_get_nt_username(u) && strcmp(pdb_get_nt_username(u), "")) - xmlNewChild(user, data->ns, "nt_username", pdb_get_nt_username(u)); + smbXmlNewChild(user, data->ns, "nt_username", pdb_get_nt_username(u)); if (pdb_get_fullname(u) && strcmp(pdb_get_fullname(u), "")) - xmlNewChild(user, data->ns, "fullname", pdb_get_fullname(u)); + smbXmlNewChild(user, data->ns, "fullname", pdb_get_fullname(u)); if (pdb_get_homedir(u) && strcmp(pdb_get_homedir(u), "")) - xmlNewChild(user, data->ns, "homedir", pdb_get_homedir(u)); + smbXmlNewChild(user, data->ns, "homedir", pdb_get_homedir(u)); if (pdb_get_dir_drive(u) && strcmp(pdb_get_dir_drive(u), "")) - xmlNewChild(user, data->ns, "dir_drive", pdb_get_dir_drive(u)); + smbXmlNewChild(user, data->ns, "dir_drive", pdb_get_dir_drive(u)); if (pdb_get_logon_script(u) && strcmp(pdb_get_logon_script(u), "")) - xmlNewChild(user, data->ns, "logon_script", + smbXmlNewChild(user, data->ns, "logon_script", pdb_get_logon_script(u)); if (pdb_get_profile_path(u) && strcmp(pdb_get_profile_path(u), "")) - xmlNewChild(user, data->ns, "profile_path", + smbXmlNewChild(user, data->ns, "profile_path", pdb_get_profile_path(u)); if (pdb_get_acct_desc(u) && strcmp(pdb_get_acct_desc(u), "")) - xmlNewChild(user, data->ns, "acct_desc", pdb_get_acct_desc(u)); + smbXmlNewChild(user, data->ns, "acct_desc", pdb_get_acct_desc(u)); if (pdb_get_workstations(u) && strcmp(pdb_get_workstations(u), "")) - xmlNewChild(user, data->ns, "workstations", + smbXmlNewChild(user, data->ns, "workstations", pdb_get_workstations(u)); if (pdb_get_unknown_str(u) && strcmp(pdb_get_unknown_str(u), "")) - xmlNewChild(user, data->ns, "unknown_str", pdb_get_unknown_str(u)); + smbXmlNewChild(user, data->ns, "unknown_str", pdb_get_unknown_str(u)); if (pdb_get_munged_dial(u) && strcmp(pdb_get_munged_dial(u), "")) - xmlNewChild(user, data->ns, "munged_dial", pdb_get_munged_dial(u)); + smbXmlNewChild(user, data->ns, "munged_dial", pdb_get_munged_dial(u)); /* Password stuff */ - pass = xmlNewChild(user, data->ns, "password", NULL); + pass = smbXmlNewChild(user, data->ns, "password", NULL); if (pdb_get_pass_last_set_time(u)) xmlNewProp(pass, "last_set", iota(pdb_get_pass_last_set_time(u))); if (pdb_get_init_flags(u, PDB_CANCHANGETIME) != PDB_DEFAULT) @@ -474,29 +495,29 @@ static NTSTATUS xmlsam_add_sam_account(struct pdb_methods *methods, SAM_ACCOUNT if (pdb_get_lanman_passwd(u)) { pdb_sethexpwd(temp, pdb_get_lanman_passwd(u), pdb_get_acct_ctrl(u)); - cur = xmlNewChild(pass, data->ns, "crypt", temp); + cur = smbXmlNewChild(pass, data->ns, "crypt", temp); xmlNewProp(cur, "type", "lanman"); } if (pdb_get_nt_passwd(u)) { pdb_sethexpwd(temp, pdb_get_nt_passwd(u), pdb_get_acct_ctrl(u)); - cur = xmlNewChild(pass, data->ns, "crypt", temp); + cur = smbXmlNewChild(pass, data->ns, "crypt", temp); xmlNewProp(cur, "type", "nt"); } - xmlNewChild(user, data->ns, "acct_ctrl", iota(pdb_get_acct_ctrl(u))); + smbXmlNewChild(user, data->ns, "acct_ctrl", iota(pdb_get_acct_ctrl(u))); if (pdb_get_logon_divs(u)) - xmlNewChild(user, data->ns, "logon_divs", + smbXmlNewChild(user, data->ns, "logon_divs", iota(pdb_get_logon_divs(u))); if (pdb_get_hours_len(u)) - xmlNewChild(user, data->ns, "hours_len", + smbXmlNewChild(user, data->ns, "hours_len", iota(pdb_get_hours_len(u))); - xmlNewChild(user, data->ns, "bad_password_count", iota(pdb_get_bad_password_count(u))); - xmlNewChild(user, data->ns, "logon_count", iota(pdb_get_logon_count(u))); - xmlNewChild(user, data->ns, "unknown_6", iota(pdb_get_unknown_6(u))); + smbXmlNewChild(user, data->ns, "bad_password_count", iota(pdb_get_bad_password_count(u))); + smbXmlNewChild(user, data->ns, "logon_count", iota(pdb_get_logon_count(u))); + smbXmlNewChild(user, data->ns, "unknown_6", iota(pdb_get_unknown_6(u))); xmlSaveFile(data->location, data->doc); return NT_STATUS_OK; diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index 7850924aacb..c3551c9d90a 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -209,6 +209,7 @@ struct table_node { #define SPL_ARCH_W32MIPS "W32MIPS" #define SPL_ARCH_W32ALPHA "W32ALPHA" #define SPL_ARCH_W32PPC "W32PPC" +#define SPL_ARCH_IA64 "IA64" static const struct table_node archi_table[]= { @@ -217,6 +218,7 @@ static const struct table_node archi_table[]= { {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 }, {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 }, {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 }, + {"Windows IA64", SPL_ARCH_IA64, 3 }, {NULL, "", -1 } }; diff --git a/source/rpc_client/cli_spoolss.c b/source/rpc_client/cli_spoolss.c index 8f5f2413dee..5303f83bf9c 100644 --- a/source/rpc_client/cli_spoolss.c +++ b/source/rpc_client/cli_spoolss.c @@ -132,6 +132,27 @@ static void decode_printer_info_3(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer, /********************************************************************** **********************************************************************/ +static void decode_printer_info_7(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer, + uint32 returned, PRINTER_INFO_7 **info) +{ + uint32 i; + PRINTER_INFO_7 *inf; + + inf=(PRINTER_INFO_7 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_7)); + memset(inf, 0, returned*sizeof(PRINTER_INFO_7)); + + prs_set_offset(&buffer->prs,0); + + for (i=0; i<returned; i++) { + smb_io_printer_info_7("", buffer, &inf[i], 0); + } + + *info=inf; +} + + +/********************************************************************** +**********************************************************************/ static void decode_port_info_1(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer, uint32 returned, PORT_INFO_1 **info) { @@ -626,6 +647,9 @@ WERROR cli_spoolss_getprinter(struct cli_state *cli, TALLOC_CTX *mem_ctx, case 3: decode_printer_info_3(mem_ctx, r.buffer, 1, &ctr->printers_3); break; + case 7: + decode_printer_info_7(mem_ctx, r.buffer, 1, &ctr->printers_7); + break; } } diff --git a/source/rpc_client/cli_srvsvc.c b/source/rpc_client/cli_srvsvc.c index 68eb17074f6..f8580d0fe2e 100644 --- a/source/rpc_client/cli_srvsvc.c +++ b/source/rpc_client/cli_srvsvc.c @@ -269,7 +269,8 @@ WERROR cli_srvsvc_net_share_add(struct cli_state *cli, TALLOC_CTX *mem_ctx, const char *netname, uint32 type, const char *remark, uint32 perms, uint32 max_uses, uint32 num_uses, - const char *path, const char *passwd) + const char *path, const char *passwd, + int level, SEC_DESC *sd) { prs_struct qbuf, rbuf; SRV_Q_NET_SHARE_ADD q; @@ -285,7 +286,8 @@ WERROR cli_srvsvc_net_share_add(struct cli_state *cli, TALLOC_CTX *mem_ctx, prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); init_srv_q_net_share_add(&q,cli->srv_name_slash, netname, type, remark, - perms, max_uses, num_uses, path, passwd); + perms, max_uses, num_uses, path, passwd, + level, sd); /* Marshall data and send request */ diff --git a/source/rpc_parse/parse_net.c b/source/rpc_parse/parse_net.c index b42b9b2a8b4..813316177ac 100644 --- a/source/rpc_parse/parse_net.c +++ b/source/rpc_parse/parse_net.c @@ -2399,11 +2399,9 @@ static BOOL net_io_sam_alias_info(const char *desc, SAM_ALIAS_INFO * info, info->hdr_sec_desc.buffer, ps, depth)) return False; - if (info->hdr_als_desc.buffer != 0) { - if (!smb_io_unistr2("uni_als_desc", &info->uni_als_desc, - info->hdr_als_name.buffer, ps, depth)) - return False; - } + if (!smb_io_unistr2("uni_als_desc", &info->uni_als_desc, + info->hdr_als_desc.buffer, ps, depth)) + return False; return True; } diff --git a/source/rpc_parse/parse_spoolss.c b/source/rpc_parse/parse_spoolss.c index ae087c7f774..2b2038d16ac 100644 --- a/source/rpc_parse/parse_spoolss.c +++ b/source/rpc_parse/parse_spoolss.c @@ -1053,6 +1053,54 @@ BOOL make_spoolss_printer_info_2(TALLOC_CTX *mem_ctx, SPOOL_PRINTER_INFO_LEVEL_2 return True; } +/******************************************************************* +create a SPOOL_PRINTER_INFO_3 struct from a PRINTER_INFO_3 struct +*******************************************************************/ + +BOOL make_spoolss_printer_info_3(TALLOC_CTX *mem_ctx, SPOOL_PRINTER_INFO_LEVEL_3 **spool_info3, + PRINTER_INFO_3 *info) +{ + + SPOOL_PRINTER_INFO_LEVEL_3 *inf; + + /* allocate the necessary memory */ + if (!(inf=(SPOOL_PRINTER_INFO_LEVEL_3*)talloc(mem_ctx, sizeof(SPOOL_PRINTER_INFO_LEVEL_3)))) { + DEBUG(0,("make_spoolss_printer_info_3: Unable to allocate SPOOL_PRINTER_INFO_LEVEL_3 sruct!\n")); + return False; + } + + inf->secdesc_ptr = (info->secdesc!=NULL)?1:0; + + *spool_info3 = inf; + + return True; +} + +/******************************************************************* +create a SPOOL_PRINTER_INFO_7 struct from a PRINTER_INFO_7 struct +*******************************************************************/ + +BOOL make_spoolss_printer_info_7(TALLOC_CTX *mem_ctx, SPOOL_PRINTER_INFO_LEVEL_7 **spool_info7, + PRINTER_INFO_7 *info) +{ + + SPOOL_PRINTER_INFO_LEVEL_7 *inf; + + /* allocate the necessary memory */ + if (!(inf=(SPOOL_PRINTER_INFO_LEVEL_7*)talloc(mem_ctx, sizeof(SPOOL_PRINTER_INFO_LEVEL_7)))) { + DEBUG(0,("make_spoolss_printer_info_7: Unable to allocate SPOOL_PRINTER_INFO_LEVEL_7 struct!\n")); + return False; + } + + inf->guid_ptr = (info->guid.buffer!=NULL)?1:0; + inf->action = info->action; + init_unistr2_from_unistr(&inf->guid, &info->guid); + + *spool_info7 = inf; + + return True; +} + /******************************************************************* * read a structure. @@ -4113,6 +4161,24 @@ BOOL make_spoolss_q_setprinter(TALLOC_CTX *mem_ctx, SPOOL_Q_SETPRINTER *q_u, q_u->devmode_ctr.devmode = NULL; #endif break; + case 3: + secdesc = info->printers_3->secdesc; + + make_spoolss_printer_info_3 (mem_ctx, &q_u->info.info_3, info->printers_3); + + q_u->secdesc_ctr = (SEC_DESC_BUF*)malloc(sizeof(SEC_DESC_BUF)); + if (!q_u->secdesc_ctr) + return False; + q_u->secdesc_ctr->ptr = (secdesc != NULL) ? 1: 0; + q_u->secdesc_ctr->max_len = (secdesc) ? sizeof(SEC_DESC) + (2*sizeof(uint32)) : 0; + q_u->secdesc_ctr->len = (secdesc) ? sizeof(SEC_DESC) + (2*sizeof(uint32)) : 0; + q_u->secdesc_ctr->sec = secdesc; + + break; + case 7: + make_spoolss_printer_info_7 (mem_ctx, &q_u->info.info_7, info->printers_7); + break; + default: DEBUG(0,("make_spoolss_q_setprinter: Unknown info level [%d]\n", level)); break; @@ -7358,7 +7424,7 @@ BOOL spoolss_io_r_enumprinterdataex(const char *desc, SPOOL_R_ENUMPRINTERDATAEX if (!prs_set_offset(ps, end_offset)) return False; - return True; + return True; } /******************************************************************* diff --git a/source/rpc_parse/parse_srv.c b/source/rpc_parse/parse_srv.c index 6349fc16325..8313c82c93d 100644 --- a/source/rpc_parse/parse_srv.c +++ b/source/rpc_parse/parse_srv.c @@ -1456,19 +1456,38 @@ BOOL srv_io_q_net_share_add(const char *desc, SRV_Q_NET_SHARE_ADD *q_n, prs_stru void init_srv_q_net_share_add(SRV_Q_NET_SHARE_ADD *q, const char *srvname, const char *netname, uint32 type, const char *remark, uint32 perms, uint32 max_uses, uint32 num_uses, - const char *path, const char *passwd) -{ - q->ptr_srv_name = 1; - init_unistr2(&q->uni_srv_name, srvname, UNI_STR_TERMINATE); - q->info.switch_value = q->info_level = 2; - - q->info.ptr_share_ctr = 1; - init_srv_share_info2(&q->info.share.info2.info_2, netname, type, - remark, perms, max_uses, num_uses, path, passwd); - init_srv_share_info2_str(&q->info.share.info2.info_2_str, netname, - remark, path, passwd); - q->ptr_err_index = 1; - q->err_index = 0; + const char *path, const char *passwd, + int level, SEC_DESC *sd) +{ + switch(level) { + case 502: { + size_t sd_size = sec_desc_size(sd); + q->ptr_srv_name = 1; + init_unistr2(&q->uni_srv_name, srvname, UNI_STR_TERMINATE); + q->info.switch_value = q->info_level = level; + q->info.ptr_share_ctr = 1; + init_srv_share_info502(&q->info.share.info502.info_502, netname, type, + remark, perms, max_uses, num_uses, path, passwd, sd, sd_size); + init_srv_share_info502_str(&q->info.share.info502.info_502_str, netname, + remark, path, passwd, sd, sd_size); + q->ptr_err_index = 1; + q->err_index = 0; + } + break; + case 2: + default: + q->ptr_srv_name = 1; + init_unistr2(&q->uni_srv_name, srvname, UNI_STR_TERMINATE); + q->info.switch_value = q->info_level = level; + q->info.ptr_share_ctr = 1; + init_srv_share_info2(&q->info.share.info2.info_2, netname, type, + remark, perms, max_uses, num_uses, path, passwd); + init_srv_share_info2_str(&q->info.share.info2.info_2_str, netname, + remark, path, passwd); + q->ptr_err_index = 1; + q->err_index = 0; + break; + } } diff --git a/source/rpc_server/srv_netlog_nt.c b/source/rpc_server/srv_netlog_nt.c index b5871a7e56d..3e0762fa43b 100644 --- a/source/rpc_server/srv_netlog_nt.c +++ b/source/rpc_server/srv_netlog_nt.c @@ -445,6 +445,7 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET * unsigned char pwd[16]; int i; uint32 acct_ctrl; + const uchar *old_pw; /* checks and updates credentials. creates reply credentials */ if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->clnt_id.cred, &srv_cred))) @@ -482,34 +483,43 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET * return NT_STATUS_ACCOUNT_DISABLED; } + cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0); + DEBUG(100,("Server password set : new given value was :\n")); for(i = 0; i < 16; i++) DEBUG(100,("%02X ", q_u->pwd[i])); DEBUG(100,("\n")); - cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0); + old_pw = pdb_get_nt_passwd(sampass); - /* lies! nt and lm passwords are _not_ the same: don't care */ - if (!pdb_set_lanman_passwd (sampass, pwd, PDB_CHANGED)) { - pdb_free_sam(&sampass); - return NT_STATUS_NO_MEMORY; - } + if (old_pw && memcmp(pwd, old_pw, 16) == 0) { + /* Avoid backend modificiations and other fun if the + client changed the password to the *same thing* */ - if (!pdb_set_nt_passwd (sampass, pwd, PDB_CHANGED)) { - pdb_free_sam(&sampass); - return NT_STATUS_NO_MEMORY; - } + ret = True; + } else { - if (!pdb_set_pass_changed_now (sampass)) { - pdb_free_sam(&sampass); - /* Not quite sure what this one qualifies as, but this will do */ - return NT_STATUS_UNSUCCESSFUL; + /* LM password should be NULL for machines */ + if (!pdb_set_lanman_passwd (sampass, NULL, PDB_CHANGED)) { + pdb_free_sam(&sampass); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_nt_passwd (sampass, pwd, PDB_CHANGED)) { + pdb_free_sam(&sampass); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_pass_changed_now (sampass)) { + pdb_free_sam(&sampass); + /* Not quite sure what this one qualifies as, but this will do */ + return NT_STATUS_UNSUCCESSFUL; + } + + become_root(); + ret = pdb_update_sam_account (sampass); + unbecome_root(); } - - become_root(); - ret = pdb_update_sam_account (sampass); - unbecome_root(); - if (ret) status = NT_STATUS_OK; diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c index ce6d9dd37ec..37617db5e8f 100644 --- a/source/rpc_server/srv_samr_nt.c +++ b/source/rpc_server/srv_samr_nt.c @@ -728,7 +728,17 @@ static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UN for (i = 0; i < num_entries; i++) { pwd = &disp_user_info[i+start_idx]; temp_name = pdb_get_username(pwd); - init_unistr2(&uni_temp_name, temp_name, UNI_STR_TERMINATE); + + /* + * usrmgr expects a non-NULL terminated string with + * trust relationships + */ + if (pdb_get_acct_ctrl(pwd) & ACB_DOMTRUST) { + init_unistr2(&uni_temp_name, temp_name, UNI_FLAGS_NONE); + } else { + init_unistr2(&uni_temp_name, temp_name, UNI_STR_TERMINATE); + } + user_sid = pdb_get_user_sid(pwd); if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) { @@ -2240,7 +2250,7 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA if (*add_script) { int add_ret; - all_string_sub(add_script, "%u", account, sizeof(account)); + all_string_sub(add_script, "%u", account, sizeof(add_script)); add_ret = smbrun(add_script,NULL); DEBUG(3,("_samr_create_user: Running the command `%s' gave %d\n", add_script, add_ret)); } @@ -3626,7 +3636,7 @@ static int smb_delete_user(const char *unix_user) pstrcpy(del_script, lp_deluser_script()); if (! *del_script) return -1; - all_string_sub(del_script, "%u", unix_user, sizeof(pstring)); + all_string_sub(del_script, "%u", unix_user, sizeof(del_script)); ret = smbrun(del_script,NULL); DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); @@ -3665,7 +3675,14 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM return NT_STATUS_NO_SUCH_USER; } - /* delete the unix side */ + /* First delete the samba side */ + if (!pdb_delete_sam_account(sam_pass)) { + DEBUG(5,("_samr_delete_dom_user:Failed to delete entry for user %s.\n", pdb_get_username(sam_pass))); + pdb_free_sam(&sam_pass); + return NT_STATUS_CANNOT_DELETE; + } + + /* Now delete the unix side */ /* * note: we don't check if the delete really happened * as the script is not necessary present @@ -3673,13 +3690,7 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM */ smb_delete_user(pdb_get_username(sam_pass)); - /* and delete the samba side */ - if (!pdb_delete_sam_account(sam_pass)) { - DEBUG(5,("_samr_delete_dom_user:Failed to delete entry for user %s.\n", pdb_get_username(sam_pass))); - pdb_free_sam(&sam_pass); - return NT_STATUS_CANNOT_DELETE; - } - + pdb_free_sam(&sam_pass); if (!close_policy_hnd(p, &q_u->user_pol)) diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c index 812939ddf50..d50237905ae 100644 --- a/source/rpc_server/srv_spoolss_nt.c +++ b/source/rpc_server/srv_spoolss_nt.c @@ -64,14 +64,14 @@ struct table_node { static Printer_entry *printers_list; typedef struct _counter_printer_0 { - ubi_dlNode Next; - ubi_dlNode Prev; + struct _counter_printer_0 *next; + struct _counter_printer_0 *prev; int snum; uint32 counter; } counter_printer_0; -static ubi_dlList counter_list; +static counter_printer_0 *counter_list; static struct cli_state notify_cli; /* print notify back-channel */ static uint32 smb_connections=0; @@ -1982,6 +1982,7 @@ static int get_version_id (char * arch) {"Windows NT R4000", "W32MIPS", 2 }, {"Windows NT Alpha_AXP", "W32ALPHA", 2 }, {"Windows NT PowerPC", "W32PPC", 2 }, + {"Windows IA64", "IA64", 3 }, {NULL, "", -1 } }; @@ -3948,9 +3949,7 @@ static BOOL construct_printer_info_0(Printer_entry *print_hnd, PRINTER_INFO_0 *p count = print_queue_length(snum, &status); /* check if we already have a counter for this printer */ - session_counter = (counter_printer_0 *)ubi_dlFirst(&counter_list); - - for(; session_counter; session_counter = (counter_printer_0 *)ubi_dlNext(session_counter)) { + for(session_counter = counter_list; session_counter; session_counter = session_counter->next) { if (session_counter->snum == snum) break; } @@ -3964,7 +3963,7 @@ static BOOL construct_printer_info_0(Printer_entry *print_hnd, PRINTER_INFO_0 *p ZERO_STRUCTP(session_counter); session_counter->snum=snum; session_counter->counter=0; - ubi_dlAddHead( &counter_list, (ubi_dlNode *)session_counter); + DLIST_ADD(counter_list, session_counter); } /* increment it */ @@ -6238,6 +6237,7 @@ WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SET DEVMODE_CTR devmode_ctr = q_u->devmode_ctr; SEC_DESC_BUF *secdesc_ctr = q_u->secdesc_ctr; uint32 command = q_u->command; + WERROR result; Printer_entry *Printer = find_printer_index_by_hnd(p, handle); @@ -6251,7 +6251,12 @@ WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SET case 0: return control_printer(handle, command, p); case 2: - return update_printer(p, handle, level, info, devmode_ctr.devmode); + result = update_printer(p, handle, level, info, devmode_ctr.devmode); + if (!W_ERROR_IS_OK(result)) + return result; + if (secdesc_ctr) + result = update_printer_sec(handle, level, info, p, secdesc_ctr); + return result; case 3: return update_printer_sec(handle, level, info, p, secdesc_ctr); diff --git a/source/rpcclient/cmd_spoolss.c b/source/rpcclient/cmd_spoolss.c index 5fa59e1903b..e99cd9f9056 100644 --- a/source/rpcclient/cmd_spoolss.c +++ b/source/rpcclient/cmd_spoolss.c @@ -39,6 +39,7 @@ static const struct table_node archi_table[]= { {"Windows NT R4000", "W32MIPS", 2 }, {"Windows NT Alpha_AXP", "W32ALPHA", 2 }, {"Windows NT PowerPC", "W32PPC", 2 }, + {"Windows IA64", "IA64", 3 }, {NULL, "", -1 } }; @@ -296,6 +297,18 @@ static void display_print_info_3(PRINTER_INFO_3 *i3) printf("\n"); } +/**************************************************************************** +printer info level 7 display function +****************************************************************************/ +static void display_print_info_7(PRINTER_INFO_7 *i7) +{ + fstring guid = ""; + rpcstr_pull(guid, i7->guid.buffer,sizeof(guid), -1, STR_TERMINATE); + printf("\tguid:[%s]\n", guid); + printf("\taction:[0x%x]\n", i7->action); +} + + /* Enumerate printers */ static WERROR cmd_spoolss_enum_printers(struct cli_state *cli, @@ -686,6 +699,9 @@ static WERROR cmd_spoolss_getprinter(struct cli_state *cli, case 3: display_print_info_3(ctr.printers_3); break; + case 7: + display_print_info_7(ctr.printers_7); + break; default: printf("unknown info level %d\n", info_level); break; @@ -1126,6 +1142,13 @@ static WERROR cmd_spoolss_enum_drivers(struct cli_state *cli, cli, mem_ctx, needed, NULL, info_level, archi_table[i].long_archi, &returned, &ctr); + if (W_ERROR_V(werror) == W_ERROR_V(WERR_INVALID_ENVIRONMENT)) { + printf ("Server does not support environment [%s]\n", + archi_table[i].long_archi); + werror = WERR_OK; + continue; + } + if (returned == 0) continue; diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk index 4c9507dcf9b..4edc7abc63a 100644 --- a/source/script/mkproto.awk +++ b/source/script/mkproto.awk @@ -132,7 +132,7 @@ END { gotstart = 1; } - if( $0 ~ /^WINBINDD_PW|^WINBINDD_GR|^NT_PRINTER_INFO_LEVEL_2|^LOGIN_CACHE|^krb5_error_code|^LDAP/ ) { + if( $0 ~ /^WINBINDD_PW|^WINBINDD_GR|^NT_PRINTER_INFO_LEVEL_2|^LOGIN_CACHE|^krb5_error_code|^LDAP|^u32/ ) { gotstart = 1; } diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c index 3983a4cbdfb..e143999a785 100644 --- a/source/smbd/blocking.c +++ b/source/smbd/blocking.c @@ -27,8 +27,9 @@ extern char *OutBuffer; notify. It consists of the requesting SMB and the expiry time. *****************************************************************************/ -typedef struct { - ubi_slNode msg_next; +typedef struct _blocking_lock_record { + struct _blocking_lock_record *next; + struct _blocking_lock_record *prev; int com_type; files_struct *fsp; time_t expire_time; @@ -40,7 +41,7 @@ typedef struct { int length; } blocking_lock_record; -static ubi_slList blocking_lock_queue = { NULL, (ubi_slNodePtr)&blocking_lock_queue, 0}; +static blocking_lock_record *blocking_lock_queue; /**************************************************************************** Destructor for the above structure. @@ -48,6 +49,7 @@ static ubi_slList blocking_lock_queue = { NULL, (ubi_slNodePtr)&blocking_lock_qu static void free_blocking_lock_record(blocking_lock_record *blr) { + DLIST_REMOVE(blocking_lock_queue, blr); SAFE_FREE(blr->inbuf); SAFE_FREE(blr); } @@ -90,7 +92,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int lock_num, uint16 lock_pid, SMB_BIG_UINT offset, SMB_BIG_UINT count) { static BOOL set_lock_msg; - blocking_lock_record *blr; + blocking_lock_record *blr, *tmp; BOOL my_lock_ctx = False; NTSTATUS status; @@ -136,7 +138,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, return False; } - ubi_slAddTail(&blocking_lock_queue, blr); + DLIST_ADD_END(blocking_lock_queue, blr, tmp); /* Ensure we'll receive messages when this is unlocked. */ if (!set_lock_msg) { @@ -516,10 +518,10 @@ static BOOL blocking_lock_record_process(blocking_lock_record *blr) void remove_pending_lock_requests_by_fid(files_struct *fsp) { - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue ); - blocking_lock_record *prev = NULL; + blocking_lock_record *blr, *next = NULL; - while(blr != NULL) { + for(blr = blocking_lock_queue; blr; blr = next) { + next = blr->next; if(blr->fsp->fnum == fsp->fnum) { DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \ @@ -529,13 +531,8 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum )); blr->lock_pid, sys_getpid(), blr->fsp->conn->cnum, blr->offset, blr->count, True, NULL, NULL); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); - continue; + free_blocking_lock_record(blr); } - - prev = blr; - blr = (blocking_lock_record *)ubi_slNext(blr); } } @@ -545,10 +542,10 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum )); void remove_pending_lock_requests_by_mid(int mid) { - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue ); - blocking_lock_record *prev = NULL; + blocking_lock_record *blr, *next = NULL; - while(blr != NULL) { + for(blr = blocking_lock_queue; blr; blr = next) { + next = blr->next; if(SVAL(blr->inbuf,smb_mid) == mid) { files_struct *fsp = blr->fsp; @@ -559,13 +556,8 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum )); brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum, blr->lock_pid, sys_getpid(), blr->fsp->conn->cnum, blr->offset, blr->count, True, NULL, NULL); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); - continue; + free_blocking_lock_record(blr); } - - prev = blr; - blr = (blocking_lock_record *)ubi_slNext(blr); } } @@ -587,7 +579,7 @@ unsigned blocking_locks_timeout(unsigned default_timeout) { unsigned timeout = default_timeout; time_t t; - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst(&blocking_lock_queue); + blocking_lock_record *blr = blocking_lock_queue; /* note that we avoid the time() syscall if there are no blocking locks */ if (!blr) @@ -595,12 +587,11 @@ unsigned blocking_locks_timeout(unsigned default_timeout) t = time(NULL); - while (blr) { + for (; blr; blr = blr->next) { if ((blr->expire_time != (time_t)-1) && (timeout > (blr->expire_time - t))) { timeout = blr->expire_time - t; } - blr = (blocking_lock_record *)ubi_slNext(blr); } if (timeout < 1) @@ -615,21 +606,19 @@ unsigned blocking_locks_timeout(unsigned default_timeout) void process_blocking_lock_queue(time_t t) { - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue ); - blocking_lock_record *prev = NULL; - - if(blr == NULL) - return; + blocking_lock_record *blr, *next = NULL; /* * Go through the queue and see if we can get any of the locks. */ - while(blr != NULL) { + for (blr = blocking_lock_queue; blr; blr = next) { connection_struct *conn = NULL; uint16 vuid; files_struct *fsp = NULL; + next = blr->next; + /* * Ensure we don't have any old chain_fsp values * sitting around.... @@ -658,8 +647,7 @@ void process_blocking_lock_queue(time_t t) blr->offset, blr->count, True, NULL, NULL); blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); + free_blocking_lock_record(blr); continue; } @@ -675,8 +663,7 @@ void process_blocking_lock_queue(time_t t) blr->lock_pid, sys_getpid(), conn->cnum, blr->offset, blr->count, True, NULL, NULL); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); + free_blocking_lock_record(blr); continue; } @@ -691,8 +678,7 @@ void process_blocking_lock_queue(time_t t) blr->lock_pid, sys_getpid(), conn->cnum, blr->offset, blr->count, True, NULL, NULL); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); + free_blocking_lock_record(blr); change_to_root_user(); continue; } @@ -709,18 +695,8 @@ void process_blocking_lock_queue(time_t t) blr->lock_pid, sys_getpid(), conn->cnum, blr->offset, blr->count, True, NULL, NULL); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); - change_to_root_user(); - continue; + free_blocking_lock_record(blr); } - change_to_root_user(); - - /* - * Move to the next in the list. - */ - prev = blr; - blr = (blocking_lock_record *)ubi_slNext(blr); } } diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c index 8ea5b9c60a3..af363d75a3f 100644 --- a/source/smbd/chgpasswd.c +++ b/source/smbd/chgpasswd.c @@ -1046,6 +1046,19 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw return NT_STATUS_ACCESS_DENIED; } + /* Use external script to check password complexity */ + if (lp_check_password_script() && *(lp_check_password_script())) { + int check_ret; + + check_ret = smbrunsecret(lp_check_password_script(), new_passwd); + DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret)); + + if (check_ret != 0) { + DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n")); + return NT_STATUS_PASSWORD_RESTRICTION; + } + } + /* * If unix password sync was requested, attempt to change * the /etc/passwd database first. Return failure if this cannot diff --git a/source/smbd/dir.c b/source/smbd/dir.c index b88f687766d..2bda42f76dc 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -986,112 +986,3 @@ int TellDir(void *p) return(dirp->pos); } - -/******************************************************************************* - This section manages a global directory cache. - (It should probably be split into a separate module. crh) -********************************************************************************/ - -typedef struct { - ubi_dlNode node; - char *path; - char *name; - char *dname; - int snum; -} dir_cache_entry; - -static ubi_dlNewList( dir_cache ); - -/***************************************************************************** - Add an entry to the directory cache. - Input: path - - name - - dname - - snum - - Output: None. -*****************************************************************************/ - -void DirCacheAdd( const char *path, const char *name, const char *dname, int snum ) -{ - int pathlen; - int namelen; - dir_cache_entry *entry; - - /* - * Allocate the structure & string space in one go so that it can be freed - * in one call to free(). - */ - pathlen = strlen(path) + 1; /* Bytes required to store path (with nul). */ - namelen = strlen(name) + 1; /* Bytes required to store name (with nul). */ - entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry ) - + pathlen - + namelen - + strlen( dname ) +1 ); - if( NULL == entry ) /* Not adding to the cache is not fatal, */ - return; /* so just return as if nothing happened. */ - - /* Set pointers correctly and load values. */ - entry->path = memcpy( (char *)&entry[1], path, strlen(path)+1 ); - entry->name = memcpy( &(entry->path[pathlen]), name, strlen(name)+1 ); - entry->dname = memcpy( &(entry->name[namelen]), dname, strlen(dname)+1 ); - entry->snum = snum; - - /* Add the new entry to the linked list. */ - (void)ubi_dlAddHead( dir_cache, entry ); - DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) ); - - /* Free excess cache entries. */ - while( DIRCACHESIZE < dir_cache->count ) - safe_free( ubi_dlRemTail( dir_cache ) ); -} - -/***************************************************************************** - Search for an entry to the directory cache. - Input: path - - name - - snum - - Output: The dname string of the located entry, or NULL if the entry was - not found. - - Notes: This uses a linear search, which is is okay because of - the small size of the cache. Use a splay tree or hash - for large caches. -*****************************************************************************/ - -char *DirCacheCheck( const char *path, const char *name, int snum ) -{ - dir_cache_entry *entry; - - for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); - NULL != entry; - entry = (dir_cache_entry *)ubi_dlNext( entry ) ) { - if( entry->snum == snum - && entry->name && 0 == strcmp( name, entry->name ) - && entry->path && 0 == strcmp( path, entry->path ) ) { - DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname)); - return( entry->dname ); - } - } - - return(NULL); -} - -/***************************************************************************** - Remove all cache entries which have an snum that matches the input. - Input: snum - - Output: None. -*****************************************************************************/ - -void DirCacheFlush(int snum) -{ - dir_cache_entry *entry; - ubi_dlNodePtr next; - - for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); - NULL != entry; ) { - next = ubi_dlNext( entry ); - if( entry->snum == snum ) - safe_free( ubi_dlRemThis( dir_cache, entry ) ); - entry = (dir_cache_entry *)next; - } -} diff --git a/source/smbd/fake_file.c b/source/smbd/fake_file.c index d3660addf11..fc874dc0867 100644 --- a/source/smbd/fake_file.c +++ b/source/smbd/fake_file.c @@ -95,9 +95,9 @@ files_struct *open_fake_file_shared1(enum FAKE_FILE_TYPE fake_file_type, connect static FAKE_FILE fake_files[] = { #ifdef WITH_QUOTAS - {FAKE_FILE_NAME_QUOTA, FAKE_FILE_TYPE_QUOTA, init_quota_handle, destroy_quota_handle}, + {FAKE_FILE_NAME_QUOTA_UNIX, FAKE_FILE_TYPE_QUOTA, init_quota_handle, destroy_quota_handle}, #endif /* WITH_QUOTAS */ - {NULL, FAKE_FILE_TYPE_NONE, NULL, NULL } + {NULL, FAKE_FILE_TYPE_NONE, NULL, NULL } }; int is_fake_file(char *fname) @@ -156,7 +156,7 @@ struct _FAKE_FILE_HANDLE *init_fake_file_handle(enum FAKE_FILE_TYPE type) void destroy_fake_file_handle(FAKE_FILE_HANDLE **fh) { if (!fh||!(*fh)) - return ; + return; if ((*fh)->free_pd) (*fh)->free_pd(&(*fh)->pd); diff --git a/source/smbd/filename.c b/source/smbd/filename.c index c411ef0f79f..279c9dd3c45 100644 --- a/source/smbd/filename.c +++ b/source/smbd/filename.c @@ -26,8 +26,7 @@ #include "includes.h" -static BOOL scan_directory(const char *path, char *name,size_t maxlength, - connection_struct *conn,BOOL docache); +static BOOL scan_directory(connection_struct *conn, const char *path, char *name,size_t maxlength); /**************************************************************************** Check if two filenames are equal. @@ -282,10 +281,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen */ if (ms_has_wild(start) || - !scan_directory(dirpath, start, - sizeof(pstring) - 1 - (start - name), - conn, - end?True:False)) { + !scan_directory(conn, dirpath, start, sizeof(pstring) - 1 - (start - name))) { if (end) { /* * An intermediate part of the name can't be found. @@ -434,8 +430,7 @@ BOOL check_name(pstring name,connection_struct *conn) If the name looks like a mangled name then try via the mangling functions ****************************************************************************/ -static BOOL scan_directory(const char *path, char *name, size_t maxlength, - connection_struct *conn,BOOL docache) +static BOOL scan_directory(connection_struct *conn, const char *path, char *name, size_t maxlength) { void *cur_dir; const char *dname; @@ -447,11 +442,6 @@ static BOOL scan_directory(const char *path, char *name, size_t maxlength, if (*path == 0) path = "."; - if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) { - safe_strcpy(name, dname, maxlength); - return(True); - } - /* * The incoming name can be mangled, and if we de-mangle it * here it will not compare correctly against the filename (name2) @@ -489,8 +479,6 @@ static BOOL scan_directory(const char *path, char *name, size_t maxlength, if ((mangled && mangled_equal(name,dname,SNUM(conn))) || fname_equal(name, dname, conn->case_sensitive)) { /* we've found the file, change it's name and return */ - if (docache) - DirCacheAdd(path,name,dname,SNUM(conn)); safe_strcpy(name, dname, maxlength); CloseDir(cur_dir); return(True); diff --git a/source/smbd/mangle_hash.c b/source/smbd/mangle_hash.c index 13ec99a917f..26ddf1b3a3d 100644 --- a/source/smbd/mangle_hash.c +++ b/source/smbd/mangle_hash.c @@ -85,23 +85,6 @@ * if that character is in the illegal characters set. * This is faster than using strchr_m(). * - * mangled_cache - Cache header used for storing mangled -> original - * reverse maps. - * - * mc_initialized - False until the mangled_cache structure has been - * initialized via a call to reset_mangled_cache(). - * - * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the - * cache. A value of 0 indicates "infinite". - * - * MANGLED_CACHE_MAX_MEMORY - Default maximum amount of memory for the - * cache. When the cache was kept as an array of 256 - * byte strings, the default cache size was 50 entries. - * This required a fixed 12.5Kbytes of memory. The - * mangled stack parameter is no longer used (though - * this might change). We're now using a fixed 16Kbyte - * maximum cache size. This will probably be much more - * than 50 entries. */ char magic_char = '~'; @@ -118,10 +101,7 @@ static BOOL ct_initialized = False; #define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK ) #define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK ) -static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } }; -static BOOL mc_initialized = False; -#define MANGLED_CACHE_MAX_ENTRIES 1024 -#define MANGLED_CACHE_MAX_MEMORY 0 +static TDB_CONTEXT *tdb_mangled_cache; /* -------------------------------------------------------------------- */ @@ -400,157 +380,69 @@ static BOOL is_mangled(const char *s) return( False ); } -/* ************************************************************************** ** - * Compare two cache keys and return a value indicating their ordinal - * relationship. - * - * Input: ItemPtr - Pointer to a comparison key. In this case, this will - * be a mangled name string. - * NodePtr - Pointer to a node in the cache. The node structure - * will be followed in memory by a mangled name string. - * - * Output: A signed integer, as follows: - * (x < 0) <==> Key1 less than Key2 - * (x == 0) <==> Key1 equals Key2 - * (x > 0) <==> Key1 greater than Key2 - * - * Notes: This is a ubiqx-style comparison routine. See ubi_BinTree for - * more info. - * - * ************************************************************************** ** - */ -static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr ) -{ - char *Key1 = (char *)ItemPtr; - char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1); - - return( StrCaseCmp( Key1, Key2 ) ); -} - -/* ************************************************************************** ** - * Free a cache entry. - * - * Input: WarrenZevon - Pointer to the entry that is to be returned to - * Nirvana. - * Output: none. - * - * Notes: This function gets around the possibility that the standard - * free() function may be implemented as a macro, or other evil - * subversions (oh, so much fun). - * - * ************************************************************************** ** - */ -static void cache_free_entry( ubi_trNodePtr WarrenZevon ) -{ - ZERO_STRUCTP(WarrenZevon); - SAFE_FREE( WarrenZevon ); -} - -/* ************************************************************************** ** - * Initializes or clears the mangled cache. - * - * Input: none. - * Output: none. - * - * Notes: There is a section below that is commented out. It shows how - * one might use lp_ calls to set the maximum memory and entry size - * of the cache. You might also want to remove the constants used - * in ubi_cacheInit() and replace them with lp_ calls. If so, then - * the calls to ubi_cacheSetMax*() would be moved into the else - * clause. Another option would be to pass in the max_entries and - * max_memory values as parameters. crh 09-Apr-1998. - * - * ************************************************************************** ** - */ +/*************************************************************************** + Initializes or clears the mangled cache. +***************************************************************************/ static void mangle_reset( void ) { - if( !mc_initialized ) { - (void)ubi_cacheInit( mangled_cache, - cache_compare, - cache_free_entry, - MANGLED_CACHE_MAX_ENTRIES, - MANGLED_CACHE_MAX_MEMORY ); - mc_initialized = True; - } else { - (void)ubi_cacheClear( mangled_cache ); - } - - /* - (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() ); - (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() ); - */ + /* We could close and re-open the tdb here... should we ? The old code did + the equivalent... JRA. */ } -/* ************************************************************************** ** - * Add a mangled name into the cache. - * - * Notes: If the mangled cache has not been initialized, then the - * function will simply fail. It could initialize the cache, - * but that's not the way it was done before I changed the - * cache mechanism, so I'm sticking with the old method. - * - * If the extension of the raw name maps directly to the - * extension of the mangled name, then we'll store both names - * *without* extensions. That way, we can provide consistent - * reverse mangling for all names that match. The test here is - * a bit more careful than the one done in earlier versions of - * mangle.c: - * - * - the extension must exist on the raw name, - * - it must be all lower case - * - it must match the mangled extension (to prove that no - * mangling occurred). - * - * crh 07-Apr-1998 - * - * ************************************************************************** ** - */ -static void cache_mangled_name( char *mangled_name, char *raw_name ) +/*************************************************************************** + Add a mangled name into the cache. + If the extension of the raw name maps directly to the + extension of the mangled name, then we'll store both names + *without* extensions. That way, we can provide consistent + reverse mangling for all names that match. The test here is + a bit more careful than the one done in earlier versions of + mangle.c: + + - the extension must exist on the raw name, + - it must be all lower case + - it must match the mangled extension (to prove that no + mangling occurred). + crh 07-Apr-1998 +**************************************************************************/ + +static void cache_mangled_name( const char mangled_name[13], char *raw_name ) { - ubi_cacheEntryPtr new_entry; - char *s1; - char *s2; - size_t mangled_len; - size_t raw_len; - size_t i; + TDB_DATA data_val; + char mangled_name_key[13]; + char *s1; + char *s2; /* If the cache isn't initialized, give up. */ - if( !mc_initialized ) + if( !tdb_mangled_cache ) return; /* Init the string lengths. */ - mangled_len = strlen( mangled_name ); - raw_len = strlen( raw_name ); + safe_strcpy(mangled_name_key, mangled_name, sizeof(mangled_name_key)-1); /* See if the extensions are unmangled. If so, store the entry * without the extension, thus creating a "group" reverse map. */ - s1 = strrchr( mangled_name, '.' ); + s1 = strrchr( mangled_name_key, '.' ); if( s1 && (s2 = strrchr( raw_name, '.' )) ) { - i = 1; + size_t i = 1; while( s1[i] && (tolower( s1[i] ) == s2[i]) ) i++; if( !s1[i] && !s2[i] ) { - mangled_len -= i; - raw_len -= i; + /* Truncate at the '.' */ + *s1 = '\0'; + *s2 = '\0'; } } /* Allocate a new cache entry. If the allocation fails, just return. */ - i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2; - new_entry = malloc( i ); - if( !new_entry ) - return; - - /* Fill the new cache entry, and add it to the cache. */ - s1 = (char *)(new_entry + 1); - s2 = (char *)&(s1[mangled_len + 1]); - 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 ); + data_val.dptr = raw_name; + data_val.dsize = strlen(raw_name)+1; + if (tdb_store_bystring(tdb_mangled_cache, mangled_name_key, data_val, TDB_REPLACE) != 0) { + DEBUG(0,("cache_mangled_name: Error storing entry %s -> %s\n", mangled_name_key, raw_name)); + } else { + DEBUG(5,("cache_mangled_name: Stored entry %s -> %s\n", mangled_name_key, raw_name)); + } } /* ************************************************************************** ** @@ -570,26 +462,25 @@ static void cache_mangled_name( char *mangled_name, char *raw_name ) static BOOL check_cache( char *s, size_t maxlen ) { - ubi_cacheEntryPtr FoundPtr; - char *ext_start = NULL; - char *found_name; - char *saved_ext = NULL; + TDB_DATA data_val; + char *ext_start = NULL; + char *saved_ext = NULL; /* If the cache isn't initialized, give up. */ - if( !mc_initialized ) + if( !tdb_mangled_cache ) return( False ); - FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); + data_val = tdb_fetch_bystring(tdb_mangled_cache, s); /* If we didn't find the name *with* the extension, try without. */ - if( !FoundPtr ) { + if(data_val.dptr == NULL || data_val.dsize == 0) { ext_start = strrchr( s, '.' ); if( ext_start ) { if((saved_ext = strdup(ext_start)) == NULL) return False; *ext_start = '\0'; - FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); + data_val = tdb_fetch_bystring(tdb_mangled_cache, s); /* * At this point s is the name without the * extension. We re-add the extension if saved_ext @@ -599,7 +490,7 @@ static BOOL check_cache( char *s, size_t maxlen ) } /* Okay, if we haven't found it we're done. */ - if( !FoundPtr ) { + if(data_val.dptr == NULL || data_val.dsize == 0) { if(saved_ext) { /* Replace the saved_ext as it was truncated. */ (void)safe_strcat( s, saved_ext, maxlen ); @@ -609,16 +500,13 @@ static BOOL check_cache( char *s, size_t maxlen ) } /* If we *did* find it, we need to copy it into the string buffer. */ - found_name = (char *)(FoundPtr + 1); - found_name += (strlen( found_name ) + 1); - - (void)safe_strcpy( s, found_name, maxlen ); + (void)safe_strcpy( s, data_val.dptr, maxlen ); if( saved_ext ) { /* Replace the saved_ext as it was truncated. */ (void)safe_strcat( s, saved_ext, maxlen ); SAFE_FREE(saved_ext); } - + SAFE_FREE(data_val.dptr); return( True ); } @@ -767,5 +655,9 @@ struct mangle_fns *mangle_hash_init(void) { mangle_reset(); + /* Create the in-memory tdb using our custom hash function. */ + tdb_mangled_cache = tdb_open_ex("mangled_cache", 1031, TDB_INTERNAL, + (O_RDWR|O_CREAT), 0644, NULL, fast_string_hash); + return &mangle_fns; } diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c index 5ff53f63007..447073acd84 100644 --- a/source/smbd/negprot.c +++ b/source/smbd/negprot.c @@ -249,6 +249,10 @@ static int reply_nt1(char *inbuf, char *outbuf) (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) { negotiate_spnego = True; capabilities |= CAP_EXTENDED_SECURITY; + add_to_common_flags2(FLAGS2_EXTENDED_SECURITY); + /* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply (already + partially constructed. */ + SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_EXTENDED_SECURITY); } capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE; diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index f717efac63e..d9e321fd968 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -762,16 +762,21 @@ 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); + + /* FAKE_FILE is a special case */ + if (fake_file_type == FAKE_FILE_TYPE_NONE) { + /* Normal file. */ + 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); + } } /* @@ -1075,7 +1080,7 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu TALLOC_CTX *mem_ctx; BOOL ret; - if (sd_len == 0) { + if (sd_len == 0 || !lp_nt_acl_support(SNUM(fsp->conn))) { return NT_STATUS_OK; } @@ -1409,7 +1414,8 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o * Now try and apply the desired SD. */ - if (sd_len && !NT_STATUS_IS_OK(status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION))) { + if (lp_nt_acl_support(SNUM(conn)) && sd_len && + !NT_STATUS_IS_OK(status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION))) { close_file(fsp,False); restore_case_semantics(conn, file_attributes); return ERROR_NT(status); diff --git a/source/smbd/process.c b/source/smbd/process.c index 60ce1499e8d..5be68d9f0a1 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -1130,7 +1130,12 @@ const char *smb_fn_name(int type) Helper functions for contruct_reply. ****************************************************************************/ -static uint32 common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_EXTENDED_SECURITY|FLAGS2_32_BIT_ERROR_CODES; +static uint32 common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_32_BIT_ERROR_CODES; + +void add_to_common_flags2(uint32 v) +{ + common_flags2 |= v; +} void remove_from_common_flags2(uint32 v) { diff --git a/source/smbd/service.c b/source/smbd/service.c index 794b5332ac5..4d111e0ea35 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -804,7 +804,8 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, /* Handle non-Dfs clients attempting connections to msdfs proxy */ if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) { - DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service)); + DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n", + service, lp_msdfs_proxy(snum))); *status = NT_STATUS_BAD_NETWORK_NAME; return NULL; } @@ -821,8 +822,6 @@ close a cnum ****************************************************************************/ void close_cnum(connection_struct *conn, uint16 vuid) { - DirCacheFlush(SNUM(conn)); - if (IS_IPC(conn)) { pipe_close_conn(conn); } else { diff --git a/source/smbd/statcache.c b/source/smbd/statcache.c index 5e78e9a4999..ba37d4927cc 100644 --- a/source/smbd/statcache.c +++ b/source/smbd/statcache.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. stat cache code Copyright (C) Andrew Tridgell 1992-2000 - Copyright (C) Jeremy Allison 1999-2000 + Copyright (C) Jeremy Allison 1999-2004 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 This program is free software; you can redistribute it and/or modify @@ -26,15 +26,7 @@ Stat cache code used in unix_convert. *****************************************************************************/ -typedef struct { - char *original_path; - char *translated_path; - size_t translated_path_length; - char names[2]; /* This is extended via malloc... */ -} stat_cache_entry; - -#define INIT_STAT_CACHE_SIZE 512 -static hash_table stat_cache; +static TDB_CONTEXT *tdb_stat_cache; /** * Add an entry into the stat cache. @@ -50,19 +42,17 @@ static hash_table stat_cache; void stat_cache_add( const char *full_orig_name, const char *orig_translated_path, BOOL case_sensitive) { - stat_cache_entry *scp; - stat_cache_entry *found_scp; char *translated_path; size_t translated_path_length; - + TDB_DATA data_val; char *original_path; size_t original_path_length; - hash_element *hash_elem; - if (!lp_stat_cache()) return; + ZERO_STRUCT(data_val); + /* * Don't cache trivial valid directory entries such as . and .. */ @@ -124,7 +114,7 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat return; } - /* we only want to store the first part of original_path, + /* we only want to index by the first part of original_path, up to the length of translated_path */ original_path[translated_path_length] = '\0'; @@ -132,55 +122,26 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat } /* - * Check this name doesn't exist in the cache before we - * add it. - */ - - if ((hash_elem = hash_lookup(&stat_cache, original_path))) { - found_scp = (stat_cache_entry *)(hash_elem->value); - if (strcmp((found_scp->translated_path), orig_translated_path) == 0) { - /* already in hash table */ - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - return; - } - /* hash collision - remove before we re-add */ - hash_remove(&stat_cache, hash_elem); - } - - /* - * New entry. + * New entry or replace old entry. */ - if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry) - +original_path_length - +translated_path_length)) == NULL) { - DEBUG(0,("stat_cache_add: Out of memory !\n")); - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - return; - } - - scp->original_path = scp->names; - /* pointer into the structure... */ - scp->translated_path = scp->names + original_path_length + 1; - safe_strcpy(scp->original_path, original_path, original_path_length); - safe_strcpy(scp->translated_path, translated_path, translated_path_length); - scp->translated_path_length = translated_path_length; + data_val.dsize = translated_path_length + 1; + data_val.dptr = translated_path; - hash_insert(&stat_cache, (char *)scp, original_path); + if (tdb_store_bystring(tdb_stat_cache, original_path, data_val, TDB_REPLACE) != 0) { + DEBUG(0,("stat_cache_add: Error storing entry %s -> %s\n", original_path, translated_path)); + } else { + DEBUG(5,("stat_cache_add: Added entry (%x:size%x) %s -> %s\n", + (unsigned int)data_val.dptr, data_val.dsize, original_path, translated_path)); + } SAFE_FREE(original_path); SAFE_FREE(translated_path); - - DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->original_path, scp->translated_path)); } /** * Look through the stat cache for an entry * - * The hash-table's internals will promote it to the top if found. - * * @param conn A connection struct to do the stat() with. * @param name The path we are attempting to cache, modified by this routine * to be correct as far as the cache can tell us @@ -195,11 +156,8 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, char **start, SMB_STRUCT_STAT *pst) { - stat_cache_entry *scp; char *chk_name; size_t namelen; - hash_element *hash_elem; - char *sp; BOOL sizechanged = False; unsigned int num_components = 0; @@ -244,8 +202,11 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, } while (1) { - hash_elem = hash_lookup(&stat_cache, chk_name); - if(hash_elem == NULL) { + TDB_DATA data_val; + char *sp; + + data_val = tdb_fetch_bystring(tdb_stat_cache, chk_name); + if(data_val.dptr == NULL || data_val.dsize == 0) { DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n", chk_name )); /* * Didn't find it - remove last component for next try. @@ -275,63 +236,84 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, return False; } } else { - scp = (stat_cache_entry *)(hash_elem->value); - DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] -> [%s]\n", chk_name, scp->translated_path )); + BOOL retval; + char *translated_path = data_val.dptr; + size_t translated_path_length = data_val.dsize - 1; + + DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] -> [%s]\n", chk_name, translated_path )); DO_PROFILE_INC(statcache_hits); - if(SMB_VFS_STAT(conn,scp->translated_path, pst) != 0) { + if(SMB_VFS_STAT(conn,translated_path, pst) != 0) { /* Discard this entry - it doesn't exist in the filesystem. */ - hash_remove(&stat_cache, hash_elem); + tdb_delete_bystring(tdb_stat_cache, chk_name); SAFE_FREE(chk_name); + SAFE_FREE(data_val.dptr); return False; } if (!sizechanged) { - memcpy(name, scp->translated_path, MIN(sizeof(pstring)-1, scp->translated_path_length)); + memcpy(name, translated_path, MIN(sizeof(pstring)-1, translated_path_length)); } else if (num_components == 0) { - pstrcpy(name, scp->translated_path); + pstrcpy(name, translated_path); } else { sp = strnrchr_m(name, '/', num_components); if (sp) { pstring last_component; pstrcpy(last_component, sp); - pstrcpy(name, scp->translated_path); + pstrcpy(name, translated_path); pstrcat(name, last_component); } else { - pstrcpy(name, scp->translated_path); + pstrcpy(name, translated_path); } } /* set pointer for 'where to start' on fixing the rest of the name */ - *start = &name[scp->translated_path_length]; + *start = &name[translated_path_length]; if(**start == '/') ++*start; - pstrcpy(dirpath, scp->translated_path); + pstrcpy(dirpath, translated_path); + retval = (namelen == translated_path_length) ? True : False; SAFE_FREE(chk_name); - return (namelen == scp->translated_path_length); + SAFE_FREE(data_val.dptr); + return retval; } } } -/*************************************************************************** ** - * Initializes or clears the stat cache. - * - * Input: none. - * Output: none. - * - * ************************************************************************** ** - */ +/*************************************************************** + Compute a hash value based on a string key value. + The function returns the bucket index number for the hashed key. + JRA. Use a djb-algorithm hash for speed. +***************************************************************/ + +u32 fast_string_hash(TDB_DATA *key) +{ + u32 n = 0; + const char *p; + for (p = key->dptr; *p != '\0'; p++) { + n = ((n << 5) + n) ^ (u32)(*p); + } + return n; +} + +/*************************************************************************** + Initializes or clears the stat cache. +**************************************************************************/ + BOOL reset_stat_cache( void ) { - static BOOL initialised; if (!lp_stat_cache()) return True; - if (initialised) { - hash_clear(&stat_cache); + if (tdb_stat_cache) { + tdb_close(tdb_stat_cache); } - initialised = hash_table_init( &stat_cache, INIT_STAT_CACHE_SIZE, - (compare_function)(strcmp)); - return initialised; + /* Create the in-memory tdb using our custom hash function. */ + tdb_stat_cache = tdb_open_ex("statcache", 1031, TDB_INTERNAL, + (O_RDWR|O_CREAT), 0644, NULL, fast_string_hash); + + if (!tdb_stat_cache) + return False; + return True; } diff --git a/source/tdb/tdb.c b/source/tdb/tdb.c index fec0b3094d3..ae4e439c903 100644 --- a/source/tdb/tdb.c +++ b/source/tdb/tdb.c @@ -276,7 +276,7 @@ static int tdb_lock(TDB_CONTEXT *tdb, int list, int ltype) if (tdb->locked[list+1].count == 0) { if (!tdb->read_only && tdb->header.rwlocks) { if (tdb_spinlock(tdb, list, ltype)) { - TDB_LOG((tdb, 0, "tdb_lock spinlock failed on list ltype=%d\n", + TDB_LOG((tdb, 0, "tdb_lock spinlock failed on list %d ltype=%d\n", list, ltype)); return -1; } @@ -329,19 +329,6 @@ static int tdb_unlock(TDB_CONTEXT *tdb, int list, int ltype) return ret; } -/* This is based on the hash algorithm from gdbm */ -static u32 tdb_hash(TDB_DATA *key) -{ - u32 value; /* Used to compute the hash value. */ - u32 i; /* Used to cycle through random values. */ - - /* Set the initial value from the key size. */ - for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++) - value = (value + (key->dptr[i] << (i*5 % 24))); - - return (1103515243 * value + 12345); -} - /* check for an out of bounds access - if it is out of bounds then see if the database has been expanded by someone else and expand if necessary @@ -1121,7 +1108,7 @@ TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key) u32 hash; /* find which hash bucket it is in */ - hash = tdb_hash(&key); + hash = tdb->hash_fn(&key); if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) return tdb_null; @@ -1153,7 +1140,7 @@ static int tdb_exists_hash(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash) int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key) { - u32 hash = tdb_hash(&key); + u32 hash = tdb->hash_fn(&key); return tdb_exists_hash(tdb, key, hash); } @@ -1413,7 +1400,7 @@ TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA oldkey) if (!tdb->travlocks.off) { /* No previous element: do normal find, and lock record */ - tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb_hash(&oldkey), F_WRLCK, &rec); + tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb->hash_fn(&oldkey), F_WRLCK, &rec); if (!tdb->travlocks.off) return tdb_null; tdb->travlocks.hash = BUCKET(rec.full_hash); @@ -1457,7 +1444,7 @@ static int tdb_delete_hash(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash) int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key) { - u32 hash = tdb_hash(&key); + u32 hash = tdb->hash_fn(&key); return tdb_delete_hash(tdb, key, hash); } @@ -1475,7 +1462,7 @@ int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) int ret = 0; /* find which hash bucket it is in */ - hash = tdb_hash(&key); + hash = tdb->hash_fn(&key); if (!tdb_keylocked(tdb, hash)) return -1; if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) @@ -1593,7 +1580,7 @@ int tdb_append(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA new_dbuf) size_t new_data_size = 0; /* find which hash bucket it is in */ - hash = tdb_hash(&key); + hash = tdb->hash_fn(&key); if (!tdb_keylocked(tdb, hash)) return -1; if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) @@ -1689,6 +1676,19 @@ static int tdb_already_open(dev_t device, return 0; } +/* This is based on the hash algorithm from gdbm */ +static u32 default_tdb_hash(TDB_DATA *key) +{ + u32 value; /* Used to compute the hash value. */ + u32 i; /* Used to cycle through random values. */ + + /* Set the initial value from the key size. */ + for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++) + value = (value + (key->dptr[i] << (i*5 % 24))); + + return (1103515243 * value + 12345); +} + /* open the database, creating it if necessary The open_flags and mode are passed straight to the open call on the @@ -1702,13 +1702,14 @@ static int tdb_already_open(dev_t device, TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode) { - return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL); + return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL); } TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode, - tdb_log_func log_fn) + tdb_log_func log_fn, + tdb_hash_func hash_fn) { TDB_CONTEXT *tdb; struct stat st; @@ -1728,7 +1729,8 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags, tdb->flags = tdb_flags; tdb->open_flags = open_flags; tdb->log_fn = log_fn; - + tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash; + if ((open_flags & O_ACCMODE) == O_WRONLY) { TDB_LOG((tdb, 0, "tdb_open_ex: can't open tdb %s write-only\n", name)); @@ -1973,7 +1975,7 @@ int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[]) /* Insertion sort by bucket */ for (i = 0; i < number; i++) { - hash = tdb_hash(&keys[i]); + hash = tdb->hash_fn(&keys[i]); for (j = 0; j < i && BUCKET(tdb->lockedkeys[j+1]) < BUCKET(hash); j++); memmove(&tdb->lockedkeys[j+2], &tdb->lockedkeys[j+1], sizeof(u32) * (i-j)); tdb->lockedkeys[j+1] = hash; @@ -2008,22 +2010,22 @@ void tdb_unlockkeys(TDB_CONTEXT *tdb) contention - it cannot guarantee how many records will be locked */ int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key) { - return tdb_lock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK); + return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); } int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key) { - return tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK); + return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); } int tdb_chainlock_read(TDB_CONTEXT *tdb, TDB_DATA key) { - return tdb_lock(tdb, BUCKET(tdb_hash(&key)), F_RDLCK); + return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); } int tdb_chainunlock_read(TDB_CONTEXT *tdb, TDB_DATA key) { - return tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_RDLCK); + return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); } @@ -2033,7 +2035,6 @@ void tdb_logging_function(TDB_CONTEXT *tdb, void (*fn)(TDB_CONTEXT *, int , cons tdb->log_fn = fn; } - /* reopen a tdb - this can be used after a fork to ensure that we have an independent seek pointer from our parent and to re-establish locks */ int tdb_reopen(TDB_CONTEXT *tdb) diff --git a/source/tdb/tdb.h b/source/tdb/tdb.h index eb120a8cecd..e8a6d201c59 100644 --- a/source/tdb/tdb.h +++ b/source/tdb/tdb.h @@ -31,6 +31,17 @@ extern "C" { #endif +#ifndef PRINTF_ATTRIBUTE +/** Use gcc attribute to check printf fns. a1 is the 1-based index of + * the parameter containing the format, and a2 the index of the first + * argument. Note that some gcc 2.x versions don't handle this + * properly **/ +#if (__GNUC__ >= 3) +#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) +#else +#define PRINTF_ATTRIBUTE(a1, a2) +#endif +#endif /* flags to tdb_store() */ #define TDB_REPLACE 1 @@ -101,18 +112,21 @@ typedef struct tdb_context { struct tdb_context *next; /* all tdbs to avoid multiple opens */ dev_t device; /* uniquely identifies this tdb */ ino_t inode; /* uniquely identifies this tdb */ - void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...); /* logging function */ + void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...) PRINTF_ATTRIBUTE(3,4); /* logging function */ + u32 (*hash_fn)(TDB_DATA *key); int open_flags; /* flags used in the open - needed by reopen */ } TDB_CONTEXT; typedef int (*tdb_traverse_func)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *); typedef void (*tdb_log_func)(TDB_CONTEXT *, int , const char *, ...); +typedef u32 (*tdb_hash_func)(TDB_DATA *key); TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode); TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode, - tdb_log_func log_fn); + tdb_log_func log_fn, + tdb_hash_func hash_fn); int tdb_reopen(TDB_CONTEXT *tdb); int tdb_reopen_all(void); diff --git a/source/tdb/tdbutil.c b/source/tdb/tdbutil.c index 09e55e2e702..e57eccfe598 100644 --- a/source/tdb/tdbutil.c +++ b/source/tdb/tdbutil.c @@ -740,7 +740,7 @@ TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags, tdb_flags |= TDB_NOMMAP; tdb = tdb_open_ex(name, hash_size, tdb_flags, - open_flags, mode, tdb_log); + open_flags, mode, tdb_log, NULL); if (!tdb) return NULL; diff --git a/source/ubiqx/ubi_BinTree.c b/source/ubiqx/ubi_BinTree.c index 8a4d4612800..e452ac10dc2 100644 --- a/source/ubiqx/ubi_BinTree.c +++ b/source/ubiqx/ubi_BinTree.c @@ -26,7 +26,16 @@ * * -------------------------------------------------------------------------- ** * - * Log: ubi_BinTree.c,v + * Log: ubi_BinTree.c,v + * Revision 4.12 2004/06/06 04:51:56 crh + * Fixed a small typo in ubi_BinTree.c (leftover testing cruft). + * Did a small amount of formatting touchup to ubi_BinTree.h. + * + * Revision 4.11 2004/06/06 03:14:09 crh + * Rewrote the ubi_btLeafNode() function. It now takes several paths in an + * effort to find a deeper leaf node. There is a small amount of extra + * overhead, but it is limited. + * * Revision 4.10 2000/06/06 20:38:40 crh * In the ReplaceNode() function, the old node header was being copied * to the new node header using a byte-by-byte copy. This was causing @@ -181,14 +190,15 @@ #include "ubi_BinTree.h" /* Header for this module. */ + /* ========================================================================== ** * Static data. */ static char ModuleID[] = "ubi_BinTree\n\ -\tRevision: 4.10 \n\ -\tDate: 2000/06/06 20:38:40 \n\ -\tAuthor: crh \n"; +\tRevision: 4.12\n\ +\tDate: 2004/06/06 04:51:56\n\ +\tAuthor: crh\n"; /* ========================================================================== ** * Internal (private) functions. @@ -1061,8 +1071,8 @@ ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ) * * Input: leader - Pointer to a node at which to start the descent. * - * Output: A pointer to a leaf node selected in a somewhat arbitrary - * manner. + * Output: A pointer to a leaf node, selected in a somewhat arbitrary + * manner but with an effort to dig deep. * * Notes: I wrote this function because I was using splay trees as a * database cache. The cache had a maximum size on it, and I @@ -1071,7 +1081,7 @@ ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ) * tend toward the bottom of the tree, meaning that leaf nodes * are good candidates for removal. (I really can't think of * any other reason to use this function.) - * + In a simple binary tree or an AVL tree, the most recently + * + In a simple binary tree, or in an AVL tree, the most recently * added nodes tend to be nearer the bottom, making this a *bad* * way to choose which node to remove from the cache. * + Randomizing the traversal order is probably a good idea. You @@ -1079,25 +1089,55 @@ ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ) * in pointers to nodes other than the root node each time. A * pointer to any node in the tree will do. Of course, if you * pass a pointer to a leaf node you'll get the same thing back. + * + In an unbalanced splay tree, if you simply traverse downward + * until you hit a leaf node it is possible to accidentally + * stumble onto a short path. The result will be a leaf node + * that is actually very high in the tree--possibly a very + * recently accessed node. Not good. This function can follow + * multiple paths in an effort to find a leaf node deeper + * in the tree. Following a single path, of course, is the + * fastest way to find a leaf node. A complete traversal would + * be sure to find the deepest leaf but would be very costly in + * terms of time. This function uses a compromise that has + * worked well in testing. * * ------------------------------------------------------------------------ ** */ { - ubi_btNodePtr follower = NULL; + #define MAXPATHS 4 /* Set higher for more maximum paths, lower for fewer. */ + ubi_trNodePtr p[MAXPATHS]; + ubi_trNodePtr q[MAXPATHS]; int whichway = ubi_trLEFT; + int paths; + int i, j; + + /* If the subtree is empty, return NULL. + */ + if( NULL == leader ) + return( NULL ); - while( NULL != leader ) + /* Initialize the p[] array with a pointer to the single node we've been + * given as a starting point. + */ + p[0] = leader; + paths = 1; + while( paths > 0 ) { - follower = leader; - leader = follower->Link[ whichway ]; - if( NULL == leader ) + for( i = 0; i < paths; i++ ) + q[i] = p[i]; + + for( i = j = 0; (i < paths) && (j < MAXPATHS); i++ ) { + if( NULL != q[i]->Link[whichway] ) + p[j++] = q[i]->Link[whichway]; whichway = ubi_trRevWay( whichway ); - leader = follower->Link[ whichway ]; + if( (j < MAXPATHS) && (NULL != q[i]->Link[whichway]) ) + p[j++] = q[i]->Link[whichway]; } + paths = j; } - return( follower ); + return( q[0] ); } /* ubi_btLeafNode */ int ubi_btModuleID( int size, char *list[] ) diff --git a/source/ubiqx/ubi_BinTree.h b/source/ubiqx/ubi_BinTree.h index c0c6d593094..43ca1a98716 100644 --- a/source/ubiqx/ubi_BinTree.h +++ b/source/ubiqx/ubi_BinTree.h @@ -28,7 +28,16 @@ * * -------------------------------------------------------------------------- ** * - * Log: ubi_BinTree.h,v + * Log: ubi_BinTree.h,v + * Revision 4.12 2004/06/06 04:51:56 crh + * Fixed a small typo in ubi_BinTree.c (leftover testing cruft). + * Did a small amount of formatting touchup to ubi_BinTree.h. + * + * Revision 4.11 2004/06/06 03:14:09 crh + * Rewrote the ubi_btLeafNode() function. It now takes several paths in an + * effort to find a deeper leaf node. There is a small amount of extra + * overhead, but it is limited. + * * Revision 4.10 2000/06/06 20:38:40 crh * In the ReplaceNode() function, the old node header was being copied * to the new node header using a byte-by-byte copy. This was causing @@ -260,6 +269,7 @@ typedef enum { * is left as is. * -------------------------------------------------------------------------- ** */ + #define ubi_trNormalize(W) ((char)( (W) - ubi_trEQUAL )) #define ubi_trAbNormal(W) ((char)( ((char)ubi_btSgn( (long)(W) )) \ + ubi_trEQUAL )) @@ -270,6 +280,7 @@ typedef enum { * DUPlicate KEY bits of the tree root flags field. * -------------------------------------------------------------------------- ** */ + #define ubi_trDups_OK(A) \ ((ubi_trDUPKEY & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE)) #define ubi_trOvwt_OK(A) \ @@ -337,6 +348,7 @@ typedef void *ubi_btItemPtr; /* A pointer to key data within a node. */ * * ------------------------------------------------------------------------- ** */ + typedef struct ubi_btNodeStruct { struct ubi_btNodeStruct *Link[ 3 ]; char gender; @@ -747,8 +759,8 @@ ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ); * * Input: leader - Pointer to a node at which to start the descent. * - * Output: A pointer to a leaf node selected in a somewhat arbitrary - * manner. + * Output: A pointer to a leaf node, selected in a somewhat arbitrary + * manner but with an effort to dig deep. * * Notes: I wrote this function because I was using splay trees as a * database cache. The cache had a maximum size on it, and I @@ -757,7 +769,7 @@ ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ); * tend toward the bottom of the tree, meaning that leaf nodes * are good candidates for removal. (I really can't think of * any other reason to use this function.) - * + In a simple binary tree or an AVL tree, the most recently + * + In a simple binary tree, or in an AVL tree, the most recently * added nodes tend to be nearer the bottom, making this a *bad* * way to choose which node to remove from the cache. * + Randomizing the traversal order is probably a good idea. You @@ -765,6 +777,17 @@ ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ); * in pointers to nodes other than the root node each time. A * pointer to any node in the tree will do. Of course, if you * pass a pointer to a leaf node you'll get the same thing back. + * + In an unbalanced splay tree, if you simply traverse downward + * until you hit a leaf node it is possible to accidentally + * stumble onto a short path. The result will be a leaf node + * that is actually very high in the tree--possibly a very + * recently accessed node. Not good. This function can follow + * multiple paths in an effort to find a leaf node deeper + * in the tree. Following a single path, of course, is the + * fastest way to find a leaf node. A complete traversal would + * be sure to find the deepest leaf but would be very costly in + * terms of time. This function uses a compromise that has + * worked well in testing. * * ------------------------------------------------------------------------ ** */ diff --git a/source/utils/net.c b/source/utils/net.c index 67b138a43be..da1339aed10 100644 --- a/source/utils/net.c +++ b/source/utils/net.c @@ -78,6 +78,11 @@ BOOL opt_localgroup = False; BOOL opt_domaingroup = False; const char *opt_newntname = ""; int opt_rid = 0; +int opt_acls = 0; +int opt_attrs = 0; +int opt_timestamps = 0; +const char *opt_exclude = NULL; +const char *opt_destination = NULL; BOOL opt_have_ip = False; struct in_addr opt_dest_ip; @@ -126,12 +131,13 @@ int net_run_function(int argc, const char **argv, struct functable *table, return usage_fn(argc, argv); } - /**************************************************************************** -connect to \\server\ipc$ +connect to \\server\service ****************************************************************************/ -NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip, - const char *server_name) +NTSTATUS connect_to_service(struct cli_state **c, struct in_addr *server_ip, + const char *server_name, + const char *service_name, + const char *service_type) { NTSTATUS nt_status; @@ -144,7 +150,7 @@ NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip, nt_status = cli_full_connection(c, NULL, server_name, server_ip, opt_port, - "IPC$", "IPC", + service_name, service_type, opt_user_name, opt_workgroup, opt_password, 0, Undefined, NULL); @@ -171,6 +177,16 @@ NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip, } } + +/**************************************************************************** +connect to \\server\ipc$ +****************************************************************************/ +NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip, + const char *server_name) +{ + return connect_to_service(c, server_ip, server_name, "IPC$", "IPC"); +} + /**************************************************************************** connect to \\server\ipc$ anonymously ****************************************************************************/ @@ -193,6 +209,42 @@ NTSTATUS connect_to_ipc_anonymous(struct cli_state **c, } } +/** + * Connect a server and open a given pipe + * + * @param cli_dst A cli_state + * @param pipe The pipe to open + * @param got_pipe boolean that stores if we got a pipe + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS connect_pipe(struct cli_state **cli_dst, int pipe_num, BOOL *got_pipe) +{ + NTSTATUS nt_status; + char *server_name = strdup("127.0.0.1"); + struct cli_state *cli_tmp = NULL; + + if (opt_destination) + server_name = strdup(opt_destination); + + /* make a connection to a named pipe */ + nt_status = connect_to_ipc(&cli_tmp, NULL, server_name); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + if (!cli_nt_session_open(cli_tmp, pipe_num)) { + DEBUG(0, ("couldn't not initialize pipe\n")); + cli_shutdown(cli_tmp); + return NT_STATUS_UNSUCCESSFUL; + } + + *cli_dst = cli_tmp; + *got_pipe = True; + + return nt_status; +} + + /**************************************************************************** Use the local machine's password for this session ****************************************************************************/ @@ -690,6 +742,12 @@ static struct functable net_func[] = { {"domain", 'D', POPT_ARG_NONE, &opt_domaingroup}, {"ntname", 'N', POPT_ARG_STRING, &opt_newntname}, {"rid", 'R', POPT_ARG_INT, &opt_rid}, + /* Options for 'net rpc share migrate' */ + {"acls", 0, POPT_ARG_NONE, &opt_acls}, + {"attrs", 0, POPT_ARG_NONE, &opt_attrs}, + {"timestamps", 0, POPT_ARG_NONE, &opt_timestamps}, + {"exclude", 'e', POPT_ARG_STRING, &opt_exclude}, + {"destination", 0, POPT_ARG_STRING, &opt_destination}, POPT_COMMON_SAMBA { 0, 0, 0, 0} diff --git a/source/utils/net.h b/source/utils/net.h index ba3a4e14352..d75a19e498e 100644 --- a/source/utils/net.h +++ b/source/utils/net.h @@ -62,6 +62,11 @@ extern BOOL opt_localgroup; extern BOOL opt_domaingroup; extern const char *opt_newntname; extern int opt_rid; +extern int opt_acls; +extern int opt_attrs; +extern int opt_timestamps; +extern const char *opt_exclude; +extern const char *opt_destination; extern BOOL opt_have_ip; extern struct in_addr opt_dest_ip; diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c index 7b8ace85b62..2efd470bbe7 100644 --- a/source/utils/net_ads.c +++ b/source/utils/net_ads.c @@ -77,9 +77,12 @@ static int net_ads_lookup(int argc, const char **argv) ads_connect(ads); - if (!ads || !ads->config.realm) { + if (!ads) { d_printf("Didn't find the cldap server!\n"); return -1; + } if (!ads->config.realm) { + ads->config.realm = opt_target_workgroup; + ads->ldap_port = 389; } return ads_cldap_netlogon(ads); diff --git a/source/utils/net_ads_cldap.c b/source/utils/net_ads_cldap.c index 1903172cf75..f3c6c5ff4d2 100644 --- a/source/utils/net_ads_cldap.c +++ b/source/utils/net_ads_cldap.c @@ -280,8 +280,9 @@ int ads_cldap_netlogon(ADS_STRUCT *ads) int sock; int ret; struct cldap_netlogon_reply reply; + const char *target = opt_host ? opt_host : inet_ntoa(ads->ldap_ip); - sock = open_udp_socket(inet_ntoa(ads->ldap_ip), ads->ldap_port); + sock = open_udp_socket(target, ads->ldap_port); if (sock == -1) { d_printf("Failed to open udp socket to %s:%u\n", inet_ntoa(ads->ldap_ip), diff --git a/source/utils/net_help.c b/source/utils/net_help.c index 38261be90a7..d6ef5e8a6c3 100644 --- a/source/utils/net_help.c +++ b/source/utils/net_help.c @@ -122,13 +122,29 @@ int net_help_share(int argc, const char **argv) "on target server\n\n" "net [<method>] share ADD <name=serverpath> [misc. options] [targets]" "\n\tAdds a share from a server (makes the export active)\n\n" - "net [<method>] share DELETE <sharename> [misc. options] [targets]\n" - "\n\tDeletes a share from a server (makes the export inactive)\n"); + "net [<method>] share DELETE <sharename> [misc. options] [targets]" + "\n\tDeletes a share from a server (makes the export inactive)\n\n" + "net [<method>] share MIGRATE FILES <sharename> [misc. options] [targets]" + "\n\tMigrates files from remote to local server\n\n" + "net [<method>] share MIGRATE SHARES <sharename> [misc. options] [targets]" + "\n\tMigrates shares from remote to local server\n\n" +/* "net [<method>] share MIGRATE SECURITY <sharename> [misc. options] [targets]" + "\n\tMigrates share-ACLs from remote to local server\n\n" */ + "net [<method>] share MIGRATE ALL <sharename> [misc. options] [targets]" + "\n\tMigrates shares (including directories, files) from remote\n" + "\tto local server\n\n" + ); net_common_methods_usage(argc, argv); net_common_flags_usage(argc, argv); d_printf( "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n" - "\t-M or --maxusers=<num>\t\tmax users allowed for share\n"); + "\t-M or --maxusers=<num>\t\tmax users allowed for share\n" + "\t --acls\t\t\tcopies ACLs as well\n" + "\t --attrs\t\t\tcopies DOS Attributes as well\n" + "\t --timestampes\t\tpreserve timestampes while copying files\n" + "\t --destination\t\tmigration target server (default: localhost)\n" + "\t-e or --exclude\t\t\tlist of shares to be excluded from mirroring\n" + "\t-v or --verbose\t\t\tgive verbose output\n"); return -1; } @@ -149,6 +165,35 @@ int net_help_file(int argc, const char **argv) return -1; } +int net_help_printer(int argc, const char **argv) +{ + d_printf("net rpc printer LIST [printer] [misc. options] [targets]\n"\ + "\tlists all printers on print-server\n\n"); + d_printf("net rpc printer DRIVER [printer] [misc. options] [targets]\n"\ + "\tlists all printer-drivers on print-server\n\n"); + d_printf("net rpc printer MIGRATE PRINTERS [printer] [misc. options] [targets]"\ + "\n\tmigrates printers from remote to local server\n\n"); + d_printf("net rpc printer MIGRATE SETTINGS [printer] [misc. options] [targets]"\ + "\n\tmigrates printer-settings from remote to local server\n\n"); + d_printf("net rpc printer MIGRATE DRIVERS [printer] [misc. options] [targets]"\ + "\n\tmigrates printer-drivers from remote to local server\n\n"); + d_printf("net rpc printer MIGRATE FORMS [printer] [misc. options] [targets]"\ + "\n\tmigrates printer-forms from remote to local server\n\n"); + d_printf("net rpc printer MIGRATE SECURITY [printer] [misc. options] [targets]"\ + "\n\tmigrates printer-ACLs from remote to local server\n\n"); + d_printf("net rpc printer MIGRATE ALL [printer] [misc. options] [targets]"\ + "\n\tmigrates drivers, forms, queues, settings and acls from\n"\ + "\tremote to local print-server\n\n"); + net_common_methods_usage(argc, argv); + net_common_flags_usage(argc, argv); + d_printf( + "\t-v or --verbose\t\t\tgive verbose output\n" + "\t --destination\t\tmigration target server (default: localhost)\n"); + + return -1; +} + + int net_help_status(int argc, const char **argv) { d_printf(" net status sessions [parseable] " diff --git a/source/utils/net_rpc.c b/source/utils/net_rpc.c index e21f79df303..1a1d76b09a0 100644 --- a/source/utils/net_rpc.c +++ b/source/utils/net_rpc.c @@ -2351,6 +2351,7 @@ rpc_share_add_internals(const DOM_SID *domain_sid, const char *domain_name, uint32 type=0; /* only allow disk shares to be added */ uint32 num_users=0, perms=0; char *password=NULL; /* don't allow a share password */ + uint32 level = 2; path = strchr(sharename, '='); if (!path) @@ -2359,7 +2360,8 @@ rpc_share_add_internals(const DOM_SID *domain_sid, const char *domain_name, result = cli_srvsvc_net_share_add(cli, mem_ctx, sharename, type, opt_comment, perms, opt_maxusers, - num_users, path, password); + num_users, path, password, + level, NULL); return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; } @@ -2492,6 +2494,486 @@ rpc_share_list_internals(const DOM_SID *domain_sid, const char *domain_name, } /** + * Migrate shares from a remote RPC server to the local RPC srever + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid acquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on completion of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +static NTSTATUS +rpc_share_migrate_shares_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + SRV_SHARE_INFO_CTR ctr_src; + ENUM_HND hnd; + uint32 type = 0; /* only allow disk shares to be added */ + uint32 num_uses = 0, perms = 0, max_uses = 0; + char *password = NULL; /* don't allow a share password */ + uint32 preferred_len = 0xffffffff, i; + BOOL got_dst_srvsvc_pipe = False; + struct cli_state *cli_dst = NULL; + uint32 level = 502; /* includes secdesc */ + SEC_DESC *share_sd = NULL; + + init_enum_hnd(&hnd, 0); + + result = cli_srvsvc_net_share_enum( + cli, mem_ctx, level, &ctr_src, preferred_len, &hnd); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* connect local PI_SRVSVC */ + nt_status = connect_pipe(&cli_dst, PI_SRVSVC, &got_dst_srvsvc_pipe); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + + for (i = 0; i < ctr_src.num_entries; i++) { + + fstring netname = "", remark = "", path = ""; + /* reset error-code */ + nt_status = NT_STATUS_UNSUCCESSFUL; + + rpcstr_pull_unistr2_fstring( + netname, &ctr_src.share.info502[i].info_502_str.uni_netname); + rpcstr_pull_unistr2_fstring( + remark, &ctr_src.share.info502[i].info_502_str.uni_remark); + rpcstr_pull_unistr2_fstring( + path, &ctr_src.share.info502[i].info_502_str.uni_path); + num_uses = ctr_src.share.info502[i].info_502.num_uses; + max_uses = ctr_src.share.info502[i].info_502.max_uses; + perms = ctr_src.share.info502[i].info_502.perms; + + + if (opt_acls) + share_sd = dup_sec_desc( + mem_ctx, ctr_src.share.info502[i].info_502_str.sd); + + /* since we do not have NetShareGetInfo implemented in samba3 we + only can skip inside the enum-ctr_src */ + if (argc == 1) { + char *one_share = talloc_strdup(mem_ctx, argv[0]); + if (!strequal(netname, one_share)) + continue; + } + + /* skip builtin shares */ + /* FIXME: should print$ be added too ? */ + if (strequal(netname,"IPC$") || strequal(netname,"ADMIN$") || + strequal(netname,"global")) + continue; + + /* only work with file-shares */ + if (!cli_send_tconX(cli, netname, "A:", "", 0)) { + d_printf("skipping [%s]: not a file share.\n", netname); + continue; + } + + if (!cli_tdis(cli)) + goto done; + + + /* finallly add the share on the dst server + please note that samba currently does not allow to + add a share without existing directory */ + + printf("migrating: [%s], path: %s, comment: %s, %s share-ACLs\n", + netname, path, remark, opt_acls ? "including" : "without" ); + + if (opt_verbose && opt_acls) + display_sec_desc(share_sd); + + result = cli_srvsvc_net_share_add(cli_dst, mem_ctx, netname, type, + remark, perms, max_uses, + num_uses, path, password, + level, share_sd); + + if (W_ERROR_V(result) == W_ERROR_V(WERR_ALREADY_EXISTS)) { + printf(" [%s] does already exist\n", netname); + continue; + } + + if (!W_ERROR_IS_OK(result)) { + printf("cannot add share: %s\n", dos_errstr(result)); + goto done; + } + + } + + nt_status = NT_STATUS_OK; + +done: + if (got_dst_srvsvc_pipe) { + cli_nt_session_close(cli_dst); + cli_shutdown(cli_dst); + } + + return nt_status; + +} + +/** + * Migrate shares from a rpc-server to another + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ +static int rpc_share_migrate_shares(int argc, const char **argv) +{ + + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + return run_rpc_command(NULL, PI_SRVSVC, 0, + rpc_share_migrate_shares_internals, + argc, argv); +} + +typedef struct copy_clistate { + TALLOC_CTX *mem_ctx; + struct cli_state *cli_share_src; + struct cli_state *cli_share_dst; + const char *cwd; +} copy_clistate; + + +/** + * Copy a file/dir + * + * @param f file_info + * @param mask current search mask + * @param state arg-pointer + * + **/ +static void copy_fn(file_info *f, const char *mask, void *state) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct copy_clistate *local_state = (struct copy_clistate *)state; + fstring filename, new_mask, dir; + + if (strequal(f->name, ".") || strequal(f->name, "..")) + return; + + DEBUG(3,("got mask: %s, name: %s\n", mask, f->name)); + + /* DIRECTORY */ + if (f->mode & aDIR) { + + DEBUG(3,("got dir: %s\n", f->name)); + + fstrcpy(dir, local_state->cwd); + fstrcat(dir, "\\"); + fstrcat(dir, f->name); + + /* create that directory */ + nt_status = net_copy_file(local_state->mem_ctx, + local_state->cli_share_src, + local_state->cli_share_dst, + dir, dir, + opt_acls? True : False, + opt_attrs? True : False, + opt_timestamps? True : False, + False); + + if (!NT_STATUS_IS_OK(nt_status)) + printf("could not copy dir %s: %s\n", + dir, nt_errstr(nt_status)); + + /* search below that directory */ + fstrcpy(new_mask, dir); + fstrcat(new_mask, "\\*"); + + if (!sync_files(local_state->mem_ctx, + local_state->cli_share_src, + local_state->cli_share_dst, + new_mask, dir)) + + printf("could not sync files\n"); + + return; + } + + + /* FILE */ + fstrcpy(filename, local_state->cwd); + fstrcat(filename, "\\"); + fstrcat(filename, f->name); + + DEBUG(3,("got file: %s\n", filename)); + + nt_status = net_copy_file(local_state->mem_ctx, + local_state->cli_share_src, + local_state->cli_share_dst, + filename, filename, + opt_acls? True : False, + opt_attrs? True : False, + opt_timestamps? True: False, + True); + + if (!NT_STATUS_IS_OK(nt_status)) + printf("could not copy file %s: %s\n", + filename, nt_errstr(nt_status)); + +} + +/** + * sync files, can be called recursivly to list files + * and then call copy_fn for each file + * + * @param mem_ctx TALLOC_CTX + * @param cli_share_src a connected share on the originating server + * @param cli_share_dst a connected share on the destination server + * @param mask the current search mask + * @param cwd the current path + * + * @return Boolean result + **/ +BOOL sync_files(TALLOC_CTX *mem_ctx, + struct cli_state *cli_share_src, + struct cli_state *cli_share_dst, + pstring mask, fstring cwd) + +{ + + uint16 attribute = aSYSTEM | aHIDDEN | aDIR; + struct copy_clistate clistate; + + clistate.mem_ctx = mem_ctx; + clistate.cli_share_src = cli_share_src; + clistate.cli_share_dst = cli_share_dst; + clistate.cwd = cwd; + + DEBUG(3,("calling cli_list with mask: %s\n", mask)); + + if (cli_list(cli_share_src, mask, attribute, copy_fn, &clistate) == -1) { + d_printf("listing %s failed with error: %s\n", + mask, cli_errstr(cli_share_src)); + return False; + } + + return True; +} + + +/** + * Sync all files inside a remote share to another share (over smb) + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passes through. + * + * @param domain_sid The domain sid acquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on completion of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +static NTSTATUS +rpc_share_migrate_files_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + SRV_SHARE_INFO_CTR ctr_src; + ENUM_HND hnd; + uint32 preferred_len = 0xffffffff, i; + uint32 level = 2; + struct cli_state *cli_share_src = NULL; + struct cli_state *cli_share_dst = NULL; + BOOL got_src_share = False; + BOOL got_dst_share = False; + pstring mask; + char *dst = NULL; + + dst = strdup(opt_destination?opt_destination:"127.0.0.1"); + + init_enum_hnd(&hnd, 0); + + result = cli_srvsvc_net_share_enum( + cli, mem_ctx, level, &ctr_src, preferred_len, &hnd); + + if (!W_ERROR_IS_OK(result)) + goto done; + + for (i = 0; i < ctr_src.num_entries; i++) { + + fstring netname = "", remark = "", path = ""; + + rpcstr_pull_unistr2_fstring( + netname, &ctr_src.share.info2[i].info_2_str.uni_netname); + rpcstr_pull_unistr2_fstring( + remark, &ctr_src.share.info2[i].info_2_str.uni_remark); + rpcstr_pull_unistr2_fstring( + path, &ctr_src.share.info2[i].info_2_str.uni_path); + + /* since we do not have NetShareGetInfo implemented in samba3 we + only can skip inside the enum-ctr_src */ + if (argc == 1) { + char *one_share = talloc_strdup(mem_ctx, argv[0]); + if (!strequal(netname, one_share)) + continue; + } + + /* skip builtin and hidden shares + In particular, one might not want to mirror whole discs :) */ + if (strequal(netname,"IPC$") || strequal(netname,"ADMIN$")) + continue; + + if (strequal(netname, "print$") || netname[1] == '$') { + d_printf("skipping [%s]: builtin/hidden share\n", netname); + continue; + } + + if (opt_exclude && in_list(netname, (char *)opt_exclude, False)) { + printf("excluding [%s]\n", netname); + continue; + } + + /* only work with file-shares */ + if (!cli_send_tconX(cli, netname, "A:", "", 0)) { + d_printf("skipping [%s]: not a file share.\n", netname); + continue; + } + + if (!cli_tdis(cli)) + return NT_STATUS_UNSUCCESSFUL; + + printf("syncing [%s] files and directories %s ACLs, %s DOS Attributes %s\n", + netname, + opt_acls ? "including" : "without", + opt_attrs ? "including" : "without", + opt_timestamps ? "(preserving timestamps)" : ""); + + + /* open share source */ + nt_status = connect_to_service(&cli_share_src, &cli->dest_ip, + cli->desthost, netname, "A:"); + if (!NT_STATUS_IS_OK(nt_status)) + goto done; + + got_src_share = True; + + + /* open share destination */ + nt_status = connect_to_service(&cli_share_dst, NULL, + dst, netname, "A:"); + if (!NT_STATUS_IS_OK(nt_status)) + goto done; + + got_dst_share = True; + + + /* now call the filesync */ + pstrcpy(mask, "\\*"); + + if (!sync_files(mem_ctx, cli_share_src, cli_share_dst, mask, NULL)) { + d_printf("could not sync files for share: %s\n", netname); + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + } + + nt_status = NT_STATUS_OK; + +done: + + if (got_src_share) + cli_shutdown(cli_share_src); + + if (got_dst_share) + cli_shutdown(cli_share_dst); + + return nt_status; + +} + +static int rpc_share_migrate_files(int argc, const char **argv) +{ + + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + return run_rpc_command(NULL, PI_SRVSVC, 0, + rpc_share_migrate_files_internals, + argc, argv); +} + +/** + * Migrate shares (including share-definitions, share-acls and files with acls/attrs) + * from one server to another + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + * + **/ +static int rpc_share_migrate_all(int argc, const char **argv) +{ + int ret; + + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + ret = run_rpc_command(NULL, PI_SRVSVC, 0, rpc_share_migrate_shares_internals, argc, argv); + if (ret) + return ret; +#if 0 + ret = run_rpc_command(NULL, PI_SRVSVC, 0, rpc_share_migrate_shares_security_internals, argc, argv); + if (ret) + return ret; +#endif + return run_rpc_command(NULL, PI_SRVSVC, 0, rpc_share_migrate_files_internals, argc, argv); +} + + +/** + * 'net rpc share migrate' entrypoint. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + **/ +static int rpc_share_migrate(int argc, const char **argv) +{ + + struct functable func[] = { + {"all", rpc_share_migrate_all}, + {"files", rpc_share_migrate_files}, + {"help", rpc_share_usage}, +/* {"security", rpc_share_migrate_security},*/ + {"shares", rpc_share_migrate_shares}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, rpc_share_usage); +} + +/** * 'net rpc share' entrypoint. * @param argc Standard main() style argc * @param argv Standard main() style argv. Initial components are already @@ -2503,6 +2985,7 @@ int net_rpc_share(int argc, const char **argv) struct functable func[] = { {"add", rpc_share_add}, {"delete", rpc_share_delete}, + {"migrate", rpc_share_migrate}, {NULL, NULL} }; @@ -3570,6 +4053,252 @@ static int rpc_vampire(int argc, const char **argv) { return run_rpc_command(NULL, PI_NETLOGON, NET_FLAGS_ANONYMOUS, rpc_vampire_internals, argc, argv); } + +/** + * Migrate everything from a print-server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + * + * The order is important ! + * To successfully add drivers the print-queues have to exist ! + * Applying ACLs should be the last step, because you're easily locked out + * + **/ +static int rpc_printer_migrate_all(int argc, const char **argv) +{ + int ret; + + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + ret = run_rpc_command(NULL, PI_SPOOLSS, 0, rpc_printer_migrate_printers_internals, argc, argv); + if (ret) + return ret; + + ret = run_rpc_command(NULL, PI_SPOOLSS, 0, rpc_printer_migrate_drivers_internals, argc, argv); + if (ret) + return ret; + + ret = run_rpc_command(NULL, PI_SPOOLSS, 0, rpc_printer_migrate_forms_internals, argc, argv); + if (ret) + return ret; + + ret = run_rpc_command(NULL, PI_SPOOLSS, 0, rpc_printer_migrate_settings_internals, argc, argv); + if (ret) + return ret; + + return run_rpc_command(NULL, PI_SPOOLSS, 0, rpc_printer_migrate_security_internals, argc, argv); + +} + +/** + * Migrate print-drivers from a print-server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ +static int rpc_printer_migrate_drivers(int argc, const char **argv) +{ + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + return run_rpc_command(NULL, PI_SPOOLSS, 0, + rpc_printer_migrate_drivers_internals, + argc, argv); +} + +/** + * Migrate print-forms from a print-server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ +static int rpc_printer_migrate_forms(int argc, const char **argv) +{ + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + return run_rpc_command(NULL, PI_SPOOLSS, 0, + rpc_printer_migrate_forms_internals, + argc, argv); +} + +/** + * Migrate printers from a print-server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ +static int rpc_printer_migrate_printers(int argc, const char **argv) +{ + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + return run_rpc_command(NULL, PI_SPOOLSS, 0, + rpc_printer_migrate_printers_internals, + argc, argv); +} + +/** + * Migrate printer-ACLs from a print-server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ +static int rpc_printer_migrate_security(int argc, const char **argv) +{ + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + return run_rpc_command(NULL, PI_SPOOLSS, 0, + rpc_printer_migrate_security_internals, + argc, argv); +} + +/** + * Migrate printer-settings from a print-server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ +static int rpc_printer_migrate_settings(int argc, const char **argv) +{ + if (!opt_host) { + printf("no server to migrate\n"); + return -1; + } + + return run_rpc_command(NULL, PI_SPOOLSS, 0, + rpc_printer_migrate_settings_internals, + argc, argv); +} + +/** + * 'net rpc printer' entrypoint. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + **/ + +int rpc_printer_migrate(int argc, const char **argv) +{ + + /* ouch: when addriver and setdriver are called from within + rpc_printer_migrate_drivers_internals, the printer-queue already + *has* to exist */ + + struct functable func[] = { + {"all", rpc_printer_migrate_all}, + {"drivers", rpc_printer_migrate_drivers}, + {"forms", rpc_printer_migrate_forms}, + {"help", rpc_printer_usage}, + {"printers", rpc_printer_migrate_printers}, + {"security", rpc_printer_migrate_security}, + {"settings", rpc_printer_migrate_settings}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, rpc_printer_usage); +} + + +/** + * List printers on a remote RPC server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ +static int rpc_printer_list(int argc, const char **argv) +{ + + return run_rpc_command(NULL, PI_SPOOLSS, 0, + rpc_printer_list_internals, + argc, argv); +} + +/** + * List printer-drivers on a remote RPC server + * + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return A shell status integer (0 for success) + **/ +static int rpc_printer_driver_list(int argc, const char **argv) +{ + + return run_rpc_command(NULL, PI_SPOOLSS, 0, + rpc_printer_driver_list_internals, + argc, argv); +} + +/** + * Display rpc printer help page. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + **/ +int rpc_printer_usage(int argc, const char **argv) +{ + return net_help_printer(argc, argv); +} + +/** + * 'net rpc printer' entrypoint. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + **/ +int net_rpc_printer(int argc, const char **argv) +{ + struct functable func[] = { + {"list", rpc_printer_list}, + {"migrate", rpc_printer_migrate}, + {"driver", rpc_printer_driver_list}, + {NULL, NULL} + }; + + if (argc == 0) + return run_rpc_command(NULL, PI_SPOOLSS, 0, + rpc_printer_list_internals, + argc, argv); + + return net_run_function(argc, argv, func, rpc_printer_usage); +} + /****************************************************************************/ @@ -3589,7 +4318,8 @@ int net_rpc_usage(int argc, const char **argv) d_printf(" net rpc user \t\t\tto add, delete and list users\n"); d_printf(" net rpc password <username> [<password>] -Uadmin_username%%admin_pass"); d_printf(" net rpc group \t\tto list groups\n"); - d_printf(" net rpc share \t\tto add, delete, and list shares\n"); + d_printf(" net rpc share \t\tto add, delete, list and migrate shares\n"); + d_printf(" net rpc printer \t\tto list and migrate printers\n"); d_printf(" net rpc file \t\t\tto list open files\n"); d_printf(" net rpc changetrustpw \tto change the trust account password\n"); d_printf(" net rpc getsid \t\tfetch the domain sid into the local secrets.tdb\n"); @@ -3659,6 +4389,7 @@ int net_rpc(int argc, const char **argv) {"group", net_rpc_group}, {"share", net_rpc_share}, {"file", net_rpc_file}, + {"printer", net_rpc_printer}, {"changetrustpw", net_rpc_changetrustpw}, {"trustdom", rpc_trustdom}, {"abortshutdown", rpc_shutdown_abort}, diff --git a/source/utils/net_rpc_printer.c b/source/utils/net_rpc_printer.c new file mode 100644 index 00000000000..51f4df7b05a --- /dev/null +++ b/source/utils/net_rpc_printer.c @@ -0,0 +1,2339 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) 2004 Guenther Deschner (gd@samba.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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" +#include "../utils/net.h" + +struct table_node { + const char *long_archi; + const char *short_archi; + int version; +}; + + +/* support itanium as well */ +static const struct table_node archi_table[]= { + + {"Windows 4.0", "WIN40", 0 }, + {"Windows NT x86", "W32X86", 2 }, + {"Windows NT R4000", "W32MIPS", 2 }, + {"Windows NT Alpha_AXP", "W32ALPHA", 2 }, + {"Windows NT PowerPC", "W32PPC", 2 }, + {"Windows IA64", "IA64", 3 }, + {NULL, "", -1 } +}; + + +/** + * The display-functions for Security-Descriptors were taken from rpcclient + * + * They reside here for debugging purpose and should + * possibly be removed later on + * + **/ +/**************************************************************************** +convert a security permissions into a string +****************************************************************************/ +char *get_sec_mask_str(uint32 type) +{ + static fstring typestr=""; + + typestr[0] = 0; + + if (type & GENERIC_ALL_ACCESS) + fstrcat(typestr, "Generic all access "); + if (type & GENERIC_EXECUTE_ACCESS) + fstrcat(typestr, "Generic execute access "); + if (type & GENERIC_WRITE_ACCESS) + fstrcat(typestr, "Generic write access "); + if (type & GENERIC_READ_ACCESS) + fstrcat(typestr, "Generic read access "); + if (type & MAXIMUM_ALLOWED_ACCESS) + fstrcat(typestr, "MAXIMUM_ALLOWED_ACCESS "); + if (type & SYSTEM_SECURITY_ACCESS) + fstrcat(typestr, "SYSTEM_SECURITY_ACCESS "); + if (type & SYNCHRONIZE_ACCESS) + fstrcat(typestr, "SYNCHRONIZE_ACCESS "); + if (type & WRITE_OWNER_ACCESS) + fstrcat(typestr, "WRITE_OWNER_ACCESS "); + if (type & WRITE_DAC_ACCESS) + fstrcat(typestr, "WRITE_DAC_ACCESS "); + if (type & READ_CONTROL_ACCESS) + fstrcat(typestr, "READ_CONTROL_ACCESS "); + if (type & DELETE_ACCESS) + fstrcat(typestr, "DELETE_ACCESS "); + + printf("\t\tSpecific bits: 0x%lx\n", (unsigned long)type&SPECIFIC_RIGHTS_MASK); + + return typestr; +} + + +/**************************************************************************** + display sec_ace structure + ****************************************************************************/ +void display_sec_ace(SEC_ACE *ace) +{ + fstring sid_str; + + printf("\tACE\n\t\ttype: "); + switch (ace->type) { + case SEC_ACE_TYPE_ACCESS_ALLOWED: + printf("ACCESS ALLOWED"); + break; + case SEC_ACE_TYPE_ACCESS_DENIED: + printf("ACCESS DENIED"); + break; + case SEC_ACE_TYPE_SYSTEM_AUDIT: + printf("SYSTEM AUDIT"); + break; + case SEC_ACE_TYPE_SYSTEM_ALARM: + printf("SYSTEM ALARM"); + break; + default: + printf("????"); + break; + } + printf(" (%d) flags: %d\n", ace->type, ace->flags); + printf("\t\tPermissions: 0x%x: %s\n", ace->info.mask, get_sec_mask_str(ace->info.mask)); + + sid_to_string(sid_str, &ace->trustee); + printf("\t\tSID: %s\n\n", sid_str); +} + + +/**************************************************************************** + display sec_acl structure + ****************************************************************************/ +void display_sec_acl(SEC_ACL *sec_acl) +{ + int i; + + printf("\tACL\tNum ACEs:\t%d\trevision:\t%x\n", + sec_acl->num_aces, sec_acl->revision); + printf("\t---\n"); + + if (sec_acl->size != 0 && sec_acl->num_aces != 0) + for (i = 0; i < sec_acl->num_aces; i++) + display_sec_ace(&sec_acl->ace[i]); + +} + +/**************************************************************************** + display sec_desc structure + ****************************************************************************/ +void display_sec_desc(SEC_DESC *sec) +{ + fstring sid_str; + + if (sec == NULL) + return; + + if (sec->sacl) { + printf("SACL\n"); + display_sec_acl(sec->sacl); + } + + if (sec->dacl) { + printf("DACL\n"); + display_sec_acl(sec->dacl); + } + + if (sec->owner_sid) { + sid_to_string(sid_str, sec->owner_sid); + printf("\tOwner SID:\t%s\n", sid_str); + } + + if (sec->grp_sid) { + sid_to_string(sid_str, sec->grp_sid); + printf("\tParent SID:\t%s\n", sid_str); + } +} + + +/** + * This display-printdriver-functions was borrowed from rpcclient/cmd_spoolss.c. + * It is here for debugging purpose and should be removed later on. + **/ + +/**************************************************************************** +printer info level 3 display function +****************************************************************************/ +static void display_print_driver_3(DRIVER_INFO_3 *i1) +{ + fstring name = ""; + fstring architecture = ""; + fstring driverpath = ""; + fstring datafile = ""; + fstring configfile = ""; + fstring helpfile = ""; + fstring dependentfiles = ""; + fstring monitorname = ""; + fstring defaultdatatype = ""; + + int length=0; + BOOL valid = True; + + if (i1 == NULL) + return; + + rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE); + rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE); + rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE); + rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE); + rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE); + rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE); + rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE); + rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE); + + d_printf ("Printer Driver Info 3:\n"); + d_printf ("\tVersion: [%x]\n", i1->version); + d_printf ("\tDriver Name: [%s]\n",name); + d_printf ("\tArchitecture: [%s]\n", architecture); + d_printf ("\tDriver Path: [%s]\n", driverpath); + d_printf ("\tDatafile: [%s]\n", datafile); + d_printf ("\tConfigfile: [%s]\n", configfile); + d_printf ("\tHelpfile: [%s]\n\n", helpfile); + + while (valid) { + rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE); + + length+=strlen(dependentfiles)+1; + + if (strlen(dependentfiles) > 0) { + d_printf ("\tDependentfiles: [%s]\n", dependentfiles); + } else { + valid = False; + } + } + + printf ("\n"); + + d_printf ("\tMonitorname: [%s]\n", monitorname); + d_printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype); + + return; +} + + +static void display_reg_value(pstring subkey, REGISTRY_VALUE value) +{ + pstring text; + + switch(value.type) { + case REG_DWORD: + d_printf("\t[%s:%s]: REG_DWORD: 0x%08x\n", subkey, value.valuename, + *((uint32 *) value.data_p)); + break; + + case REG_SZ: + rpcstr_pull(text, value.data_p, sizeof(text), value.size, + STR_TERMINATE); + d_printf("\t[%s:%s]: REG_SZ: %s\n", subkey, value.valuename, text); + break; + + case REG_BINARY: + d_printf("\t[%s:%s]: REG_BINARY: unknown length value not displayed\n", + subkey, value.valuename); + break; + + case REG_MULTI_SZ: { + uint16 *curstr = (uint16 *) value.data_p; + uint8 *start = value.data_p; + d_printf("\t[%s:%s]: REG_MULTI_SZ:\n", subkey, value.valuename); + while ((*curstr != 0) && + ((uint8 *) curstr < start + value.size)) { + rpcstr_pull(text, curstr, sizeof(text), -1, + STR_TERMINATE); + d_printf("%s\n", text); + curstr += strlen(text) + 1; + } + } + break; + + default: + d_printf("\t%s: unknown type %d\n", value.valuename, value.type); + } + +} + + +/** + * Copies ACLs, DOS-attributes and timestamps from one + * file or directory from one connected share to another connected share + * + * @param mem_ctx A talloc-context + * @param cli_share_src A connected cli_state + * @param cli_share_dst A connected cli_state + * @param src_file The source file-name + * @param dst_file The destination file-name + * @param copy_acls Whether to copy acls + * @param copy_attrs Whether to copy DOS attributes + * @param copy_timestamps Whether to preserve timestamps + * @param is_file Whether this file is a file or a dir + * + * @return Normal NTSTATUS return. + **/ +static NTSTATUS +net_copy_fileattr(TALLOC_CTX *mem_ctx, + struct cli_state *cli_share_src, + struct cli_state *cli_share_dst, + char *src_name, char *dst_name, + BOOL copy_acls, BOOL copy_attrs, + BOOL copy_timestamps, BOOL is_file) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + int fnum_src = 0; + int fnum_dst = 0; + SEC_DESC *sd = NULL; + uint16 attr; + time_t atime, ctime, mtime; + + + if (!copy_timestamps && !copy_acls && !copy_attrs) + return NT_STATUS_OK; + + + /* open file/dir on the originating server */ + + DEBUGADD(3,("opening %s %s on originating server\n", + is_file?"file":"dir", src_name)); + + fnum_src = cli_nt_create(cli_share_src, src_name, READ_CONTROL_ACCESS); + if (fnum_src == -1) { + DEBUGADD(0,("cannot open %s %s on originating server %s\n", + is_file?"file":"dir", src_name, cli_errstr(cli_share_src))); + nt_status = cli_nt_error(cli_share_src); + goto out; + } + + + if (copy_acls) { + + /* get the security descriptor */ + sd = cli_query_secdesc(cli_share_src, fnum_src, mem_ctx); + if (!sd) { + DEBUG(0,("failed to get security descriptor: %s\n", + cli_errstr(cli_share_src))); + nt_status = cli_nt_error(cli_share_src); + goto out; + } + + if (opt_verbose && DEBUGLEVEL >= 3) + display_sec_desc(sd); + } + + + if (copy_attrs || copy_timestamps) { + + /* get file attributes */ + if (!cli_getattrE(cli_share_src, fnum_src, &attr, NULL, + &ctime, &atime, &mtime)) { + DEBUG(0,("failed to get file-attrs: %s\n", + cli_errstr(cli_share_src))); + nt_status = cli_nt_error(cli_share_src); + goto out; + } + } + + + /* open the file/dir on the destination server */ + + fnum_dst = cli_nt_create(cli_share_dst, dst_name, WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS); + if (fnum_dst == -1) { + DEBUG(0,("failed to open %s on the destination server: %s: %s\n", + is_file?"file":"dir", dst_name, cli_errstr(cli_share_dst))); + nt_status = cli_nt_error(cli_share_dst); + goto out; + } + + if (copy_timestamps) { + + /* set timestamps */ + if (!cli_setattrE(cli_share_dst, fnum_dst, ctime, atime, mtime)) { + DEBUG(0,("failed to set file-attrs (timestamps): %s\n", + cli_errstr(cli_share_dst))); + nt_status = cli_nt_error(cli_share_dst); + goto out; + } + } + + if (copy_acls) { + + /* set acls */ + if (!cli_set_secdesc(cli_share_dst, fnum_dst, sd)) { + DEBUG(0,("could not set secdesc on %s: %s\n", + dst_name, cli_errstr(cli_share_dst))); + nt_status = cli_nt_error(cli_share_dst); + goto out; + } + } + + if (copy_attrs) { + + /* set attrs */ + if (!cli_setatr(cli_share_dst, dst_name, attr, 0)) { + DEBUG(0,("failed to set file-attrs: %s\n", + cli_errstr(cli_share_dst))); + nt_status = cli_nt_error(cli_share_dst); + goto out; + } + } + + + /* closing files */ + + if (!cli_close(cli_share_src, fnum_src)) { + d_printf("could not close %s on originating server: %s\n", + is_file?"file":"dir", cli_errstr(cli_share_src)); + nt_status = cli_nt_error(cli_share_src); + goto out; + } + + if (!cli_close(cli_share_dst, fnum_dst)) { + d_printf("could not close %s on destination server: %s\n", + is_file?"file":"dir", cli_errstr(cli_share_dst)); + nt_status = cli_nt_error(cli_share_dst); + goto out; + } + + + nt_status = NT_STATUS_OK; + +out: + + /* cleaning up */ + if (fnum_src) + cli_close(cli_share_src, fnum_src); + + if (fnum_dst) + cli_close(cli_share_dst, fnum_dst); + + return nt_status; +} + + +/** + * Copy a file or directory from a connected share to another connected share + * + * @param mem_ctx A talloc-context + * @param cli_share_src A connected cli_state + * @param cli_share_dst A connected cli_state + * @param src_file The source file-name + * @param dst_file The destination file-name + * @param copy_acls Whether to copy acls + * @param copy_attrs Whether to copy DOS attributes + * @param copy_timestamps Whether to preserve timestamps + * @param is_file Whether this file is a file or a dir + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS net_copy_file(TALLOC_CTX *mem_ctx, + struct cli_state *cli_share_src, + struct cli_state *cli_share_dst, + char *src_name, char *dst_name, + BOOL copy_acls, BOOL copy_attrs, + BOOL copy_timestamps, BOOL is_file) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + int fnum_src = 0; + int fnum_dst = 0; + static int io_bufsize = 64512; + int read_size = io_bufsize; + char *data = NULL; + off_t start = 0; + off_t nread = 0; + + + if (!src_name || !dst_name) + goto out; + + if (cli_share_dst == NULL || cli_share_dst == NULL) + goto out; + + + /* open on the originating server */ + DEBUGADD(3,("opening %s %s on originating server\n", + is_file ? "file":"dir", src_name)); + if (is_file) + fnum_src = cli_open(cli_share_src, src_name, O_RDONLY, DENY_NONE); + else + fnum_src = cli_nt_create(cli_share_src, src_name, READ_CONTROL_ACCESS); + + if (fnum_src == -1) { + DEBUGADD(0,("cannot open file %s on originating server %s\n", + src_name, cli_errstr(cli_share_src))); + nt_status = cli_nt_error(cli_share_src); + goto out; + } + + + if (is_file) { + + /* open file on the destination server */ + DEBUGADD(3,("opening file %s on destination server\n", dst_name)); + fnum_dst = cli_open(cli_share_dst, dst_name, + O_RDWR|O_CREAT|O_TRUNC, DENY_NONE); + + if (fnum_dst == -1) { + DEBUGADD(1,("cannot create file %s on destination server: %s\n", + dst_name, cli_errstr(cli_share_dst))); + nt_status = cli_nt_error(cli_share_dst); + goto out; + } + + /* allocate memory */ + if (!(data = (char *)malloc(read_size))) { + d_printf("malloc fail for size %d\n", read_size); + nt_status = NT_STATUS_NO_MEMORY; + goto out; + } + + } + + + if (opt_verbose) { + + d_printf("copying [\\\\%s\\%s%s] => [\\\\%s\\%s%s] " + "%s ACLs and %s DOS Attributes %s\n", + cli_share_src->desthost, cli_share_src->share, src_name, + cli_share_dst->desthost, cli_share_dst->share, dst_name, + copy_acls ? "with" : "without", + copy_attrs ? "with" : "without", + copy_timestamps ? "(preserving timestamps)" : "" ); + } + + + while (is_file) { + + /* copying file */ + int n, ret; + n = cli_read(cli_share_src, fnum_src, data, nread + start, + read_size); + + if (n <= 0) + break; + + ret = cli_write(cli_share_dst, fnum_dst, 0, data, + nread + start, n); + + if (n != ret) { + d_printf("Error writing file: %s\n", + cli_errstr(cli_share_dst)); + nt_status = cli_nt_error(cli_share_dst); + goto out; + } + + nread += n; + } + + + if (!is_file && !cli_chkpath(cli_share_dst, dst_name)) { + + /* creating dir */ + DEBUGADD(3,("creating dir %s on the destination server\n", + dst_name)); + + if (!cli_mkdir(cli_share_dst, dst_name)) { + DEBUG(0,("cannot create directory %s: %s\n", + dst_name, cli_errstr(cli_share_dst))); + nt_status = NT_STATUS_NO_SUCH_FILE; + } + + if (!cli_chkpath(cli_share_dst, dst_name)) { + d_printf("cannot check for directory %s: %s\n", + dst_name, cli_errstr(cli_share_dst)); + goto out; + } + } + + + /* closing files */ + if (!cli_close(cli_share_src, fnum_src)) { + d_printf("could not close file on originating server: %s\n", + cli_errstr(cli_share_src)); + nt_status = cli_nt_error(cli_share_src); + goto out; + } + + if (is_file && !cli_close(cli_share_dst, fnum_dst)) { + d_printf("could not close file on destination server: %s\n", + cli_errstr(cli_share_dst)); + nt_status = cli_nt_error(cli_share_dst); + goto out; + } + + /* possibly we have to copy some file-attributes / acls / sd */ + nt_status = net_copy_fileattr(mem_ctx, cli_share_src, cli_share_dst, + src_name, dst_name, copy_acls, + copy_attrs, copy_timestamps, is_file); + if (!NT_STATUS_IS_OK(nt_status)) + goto out; + + + nt_status = NT_STATUS_OK; + +out: + + /* cleaning up */ + if (fnum_src) + cli_close(cli_share_src, fnum_src); + + if (fnum_dst) + cli_close(cli_share_dst, fnum_dst); + + SAFE_FREE(data); + + return nt_status; +} + + +/** + * Copy a driverfile from on connected share to another connected share + * This silently assumes that a driver-file is picked up from + * + * \\src_server\print$\{arch}\{version}\file + * + * and copied to + * + * \\dst_server\print$\{arch}\file + * + * to be added via setdriver-calls later. + * @param mem_ctx A talloc-context + * @param cli_share_src A cli_state connected to source print$-share + * @param cli_share_dst A cli_state connected to destination print$-share + * @param file The file-name to be copied + * @param short_archi The name of the driver-architecture (short form) + * + * @return Normal NTSTATUS return. + **/ +static NTSTATUS net_copy_driverfile(TALLOC_CTX *mem_ctx, + struct cli_state *cli_share_src, + struct cli_state *cli_share_dst, + char *file, const char *short_archi) { + + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + const char *p; + char *src_name; + char *dst_name; + fstring version; + fstring filename; + fstring tok; + + /* scroll through the file until we have the part + beyond archi_table.short_archi */ + p = file; + while (next_token(&p, tok, "\\", sizeof(tok))) { + if (strequal(tok, short_archi)) { + next_token(&p, version, "\\", sizeof(version)); + next_token(&p, filename, "\\", sizeof(filename)); + } + } + + /* build source file name */ + if (asprintf(&src_name, "\\%s\\%s\\%s", short_archi, version, filename) < 0 ) + return NT_STATUS_NO_MEMORY; + + + /* create destination file name */ + if (asprintf(&dst_name, "\\%s\\%s", short_archi, filename) < 0 ) + return NT_STATUS_NO_MEMORY; + + + /* finally copy the file */ + nt_status = net_copy_file(mem_ctx, cli_share_src, cli_share_dst, + src_name, dst_name, False, False, False, True); + if (!NT_STATUS_IS_OK(nt_status)) + goto out; + + nt_status = NT_STATUS_OK; + +out: + SAFE_FREE(src_name); + SAFE_FREE(dst_name); + + return nt_status; +} + + +/** + * Check for existing Architecture directory on a given server + * + * @param cli_share A cli_state connected to a print$-share + * @param short_archi The Architecture for the print-driver + * + * @return Normal NTSTATUS return. + **/ +static NTSTATUS +check_arch_dir(struct cli_state *cli_share, const char *short_archi) +{ + + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + char *dir; + + if (asprintf(&dir, "\\%s", short_archi) < 0) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10,("creating print-driver dir for architecture: %s\n", + short_archi)); + + if (!cli_mkdir(cli_share, dir)) { + DEBUG(1,("cannot create directory %s: %s\n", + dir, cli_errstr(cli_share))); + nt_status = NT_STATUS_NO_SUCH_FILE; + } + + if (!cli_chkpath(cli_share, dir)) { + d_printf("cannot check %s: %s\n", + dir, cli_errstr(cli_share)); + goto out; + } + + nt_status = NT_STATUS_OK; + +out: + SAFE_FREE(dir); + return nt_status; +} + + +/** + * Copy a print-driver (level 3) from one connected print$-share to another + * connected print$-share + * + * @param mem_ctx A talloc-context + * @param cli_share_src A cli_state connected to a print$-share + * @param cli_share_dst A cli_state connected to a print$-share + * @param short_archi The Architecture for the print-driver + * @param i1 The DRIVER_INFO_3-struct + * + * @return Normal NTSTATUS return. + **/ +static NTSTATUS +copy_print_driver_3(TALLOC_CTX *mem_ctx, + struct cli_state *cli_share_src, + struct cli_state *cli_share_dst, + const char *short_archi, DRIVER_INFO_3 *i1) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + int length = 0; + BOOL valid = True; + + fstring name = ""; + fstring driverpath = ""; + fstring datafile = ""; + fstring configfile = ""; + fstring helpfile = ""; + fstring dependentfiles = ""; + + if (i1 == NULL) + return nt_status; + + rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE); + rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE); + rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE); + rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE); + rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE); + + + if (opt_verbose) + d_printf("copying driver: [%s], for architecture: [%s], version: [%d]\n", + name, short_archi, i1->version); + + nt_status = net_copy_driverfile(mem_ctx, cli_share_src, cli_share_dst, + driverpath, short_archi); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + nt_status = net_copy_driverfile(mem_ctx, cli_share_src, cli_share_dst, + datafile, short_archi); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + nt_status = net_copy_driverfile(mem_ctx, cli_share_src, cli_share_dst, + configfile, short_archi); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + nt_status = net_copy_driverfile(mem_ctx, cli_share_src, cli_share_dst, + helpfile, short_archi); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + while (valid) { + rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE); + length+=strlen(dependentfiles)+1; + if (strlen(dependentfiles) > 0) { + + nt_status = net_copy_driverfile(mem_ctx, + cli_share_src, cli_share_dst, + dependentfiles, short_archi); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + } else { + valid = False; + } + } + + return NT_STATUS_OK; +} + + +/** + * net_spoolss-functions + * ===================== + * + * the net_spoolss-functions aim to simplify spoolss-client-functions + * required during the migration-process wrt buffer-sizes, returned + * error-codes, etc. + * + * this greatly reduces the complexitiy of the migrate-functions. + * + **/ + +static BOOL +net_spoolss_enum_printers(struct cli_state *cli, TALLOC_CTX *mem_ctx, + char *name, uint32 flags, uint32 level, + uint32 *num_printers, PRINTER_INFO_CTR *ctr) +{ + + WERROR result; + uint32 needed; + + /* enum printers */ + result = cli_spoolss_enum_printers( + cli, mem_ctx, 0, &needed, name, flags, + level, num_printers, ctr); + + if (W_ERROR_V(result) == W_ERROR_V(WERR_INSUFFICIENT_BUFFER)) + result = cli_spoolss_enum_printers( + cli, mem_ctx, needed, NULL, name, flags, + level, num_printers, ctr); + + + if (!W_ERROR_IS_OK(result)) { + printf("cannot enum printers: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_open_printer_ex(struct cli_state *cli, TALLOC_CTX *mem_ctx, + const char *printername, const char *datatype, + uint32 access_required, const char *servername, + const char *username, POLICY_HND *hnd) +{ + WERROR result; + + fstring servername2; + slprintf(servername2, sizeof(servername2)-1, "\\\\%s", cli->desthost); + + DEBUG(10,("connecting to: %s as %s for %s and access: %x\n", + servername2, username, printername, access_required)); + + /* open printer */ + result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", access_required, + servername2, username, hnd); + + /* be more verbose */ + if (W_ERROR_V(result) == W_ERROR_V(WERR_ACCESS_DENIED)) { + d_printf("no access to printer [%s] on [%s] for user [%s] granted\n", + printername, servername2, username); + return False; + } + + if (!W_ERROR_IS_OK(result)) { + d_printf("cannot open printer %s on server %s: %s\n", + printername, servername2, dos_errstr(result)); + return False; + } + + DEBUG(2,("got printer handle for printer: %s, server: %s\n", + printername, servername2)); + + return True; +} + + +static BOOL +net_spoolss_getprinter(struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hnd, uint32 level, + PRINTER_INFO_CTR *ctr) +{ + WERROR result; + uint32 needed; + + /* getprinter call */ + result = cli_spoolss_getprinter(cli, + mem_ctx, 0, &needed, hnd, level, ctr); + + if (W_ERROR_V(result) == W_ERROR_V(WERR_INSUFFICIENT_BUFFER)) + result = cli_spoolss_getprinter(cli, + mem_ctx, needed, NULL, hnd, level, ctr); + + if (!W_ERROR_IS_OK(result)) { + printf("cannot get printer-info: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_setprinter(struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hnd, uint32 level, + PRINTER_INFO_CTR *ctr) +{ + WERROR result; + + /* setprinter call */ + result = cli_spoolss_setprinter(cli, mem_ctx, hnd, level, ctr, 0); + + if (!W_ERROR_IS_OK(result)) { + printf("cannot set printer-info: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_setprinterdata(struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hnd, REGISTRY_VALUE *value) +{ + WERROR result; + + /* setprinterdata call */ + result = cli_spoolss_setprinterdata(cli, mem_ctx, hnd, value); + + if (!W_ERROR_IS_OK(result)) { + printf ("unable to set printerdata: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_enumprinterkey(struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hnd, const char *keyname, + uint16 **keylist) +{ + WERROR result; + uint32 needed, len; + + /* enumprinterkey call */ + result = cli_spoolss_enumprinterkey( + cli, mem_ctx, 0, &needed, hnd, keyname, NULL, NULL); + + if (W_ERROR_V(result) == W_ERROR_V(WERR_MORE_DATA)) + result = cli_spoolss_enumprinterkey( + cli, mem_ctx, needed, NULL, hnd, keyname, keylist, + &len); + + if (!W_ERROR_IS_OK(result)) { + printf("enumprinterkey failed: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_enumprinterdataex(struct cli_state *cli, TALLOC_CTX *mem_ctx, + uint32 offered, + POLICY_HND *hnd, const char *keyname, + REGVAL_CTR *ctr) +{ + WERROR result; + uint32 needed; + + /* enumprinterdataex call */ + result = cli_spoolss_enumprinterdataex( + cli, mem_ctx, 0, &needed, hnd, keyname, NULL); + + if (W_ERROR_V(result) == W_ERROR_V(WERR_MORE_DATA)) + result = cli_spoolss_enumprinterdataex( + cli, mem_ctx, needed, NULL, hnd, keyname, ctr); + + if (!W_ERROR_IS_OK(result)) { + printf("enumprinterdataex failed: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_setprinterdataex(struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hnd, char *keyname, + REGISTRY_VALUE *value) +{ + WERROR result; + + /* setprinterdataex call */ + result = cli_spoolss_setprinterdataex(cli, mem_ctx, hnd, + keyname, value); + + if (!W_ERROR_IS_OK(result)) { + printf("could not set printerdataex: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_enumforms(struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hnd, int level, uint32 *num_forms, + FORM_1 **forms) + +{ + WERROR result; + uint32 needed; + + /* enumforms call */ + result = cli_spoolss_enumforms( + cli, mem_ctx, 0, &needed, hnd, level, num_forms, forms); + + if (W_ERROR_V(result) == W_ERROR_V(WERR_INSUFFICIENT_BUFFER)) + result = cli_spoolss_enumforms( + cli, mem_ctx, needed, NULL, hnd, level, + num_forms, forms); + + if (!W_ERROR_IS_OK(result)) { + printf("could not enum forms: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_enumprinterdrivers (struct cli_state *cli, TALLOC_CTX *mem_ctx, + uint32 level, const char *env, + uint32 *num_drivers, + PRINTER_DRIVER_CTR *ctr) +{ + WERROR result; + uint32 needed; + + /* enumprinterdrivers call */ + result = cli_spoolss_enumprinterdrivers( + cli, mem_ctx, 0, &needed, level, + env, num_drivers, ctr); + + if (W_ERROR_V(result) == W_ERROR_V(WERR_INSUFFICIENT_BUFFER)) + result = cli_spoolss_enumprinterdrivers( + cli, mem_ctx, needed, NULL, level, + env, num_drivers, ctr); + + if (!W_ERROR_IS_OK(result)) { + printf("cannot enum drivers: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + + +static BOOL +net_spoolss_getprinterdriver(struct cli_state *cli, + TALLOC_CTX *mem_ctx, + POLICY_HND *hnd, uint32 level, + const char *env, int version, + PRINTER_DRIVER_CTR *ctr) +{ + WERROR result; + uint32 needed; + + /* getprinterdriver call */ + result = cli_spoolss_getprinterdriver( + cli, mem_ctx, 0, &needed, hnd, level, + env, version, ctr); + + if (W_ERROR_V(result) == W_ERROR_V(WERR_INSUFFICIENT_BUFFER)) + result = cli_spoolss_getprinterdriver( + cli, mem_ctx, needed, NULL, hnd, level, + env, version, ctr); + + if (!W_ERROR_IS_OK(result)) { + DEBUG(1,("cannot get driver (for architecture: %s): %s\n", + env, dos_errstr(result))); + if (W_ERROR_V(result) != W_ERROR_V(WERR_UNKNOWN_PRINTER_DRIVER)) { + printf("cannot get driver: %s\n", dos_errstr(result)); + } + return False; + } + + return True; +} + + +static BOOL +net_spoolss_addprinterdriver(struct cli_state *cli, + TALLOC_CTX *mem_ctx, uint32 level, + PRINTER_DRIVER_CTR *ctr) +{ + WERROR result; + + /* addprinterdriver call */ + result = cli_spoolss_addprinterdriver(cli, mem_ctx, level, ctr); + + /* be more verbose */ + if (W_ERROR_V(result) == W_ERROR_V(WERR_ACCESS_DENIED)) { + printf("You are not allowed to add drivers\n"); + return False; + } + if (!W_ERROR_IS_OK(result)) { + printf("cannot add driver: %s\n", dos_errstr(result)); + return False; + } + + return True; +} + +/** + * abstraction function to get uint32 num_printers and PRINTER_INFO_CTR ctr + * for a single printer or for all printers depending on argc/argv + **/ +static BOOL +get_printer_info(struct cli_state *cli, TALLOC_CTX *mem_ctx, + int level, int argc, const char **argv, + uint32 *num_printers, PRINTER_INFO_CTR *ctr) +{ + + char *sharename; + fstring servername; + POLICY_HND hnd; + + /* no arguments given, enumerate all printers */ + if (argc == 0) { + + if (!net_spoolss_enum_printers(cli, mem_ctx, NULL, + PRINTER_ENUM_LOCAL|PRINTER_ENUM_SHARED, + level, num_printers, ctr)) + return False; + + goto out; + } + + + /* argument given, get a single printer by name */ + sharename = strdup(argv[0]); + + if (!net_spoolss_open_printer_ex(cli, mem_ctx, sharename, "", + MAXIMUM_ALLOWED_ACCESS, servername, + cli->user_name, &hnd)) + return False; + + if (!net_spoolss_getprinter(cli, mem_ctx, &hnd, level, ctr)) { + cli_spoolss_close_printer(cli, mem_ctx, &hnd); + return False; + } + + cli_spoolss_close_printer(cli, mem_ctx, &hnd); + + *num_printers = 1; + +out: + DEBUG(3,("got %d printers\n", *num_printers)); + + return True; + +} + + +/** + * List print-queues (including local printers that are not shared) + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passed through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS rpc_printer_list_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + uint32 i, num_printers; + uint32 level = 2; + pstring printername, sharename; + PRINTER_INFO_CTR ctr; + + printf("listing printers\n"); + + if (!get_printer_info(cli, mem_ctx, level, argc, argv, &num_printers, &ctr)) + return nt_status; + + for (i = 0; i < num_printers; i++) { + + /* do some initialization */ + rpcstr_pull(printername, ctr.printers_2[i].printername.buffer, + sizeof(printername), -1, STR_TERMINATE); + rpcstr_pull(sharename, ctr.printers_2[i].sharename.buffer, + sizeof(sharename), -1, STR_TERMINATE); + + d_printf("printer %d: %s, shared as: %s\n", + i+1, printername, sharename); + } + + return NT_STATUS_OK; +} + + +/** + * List printer-drivers from a server + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passed through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS rpc_printer_driver_list_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + uint32 i; + uint32 level = 3; + PRINTER_DRIVER_CTR drv_ctr_enum; + int d; + + ZERO_STRUCT(drv_ctr_enum); + + + printf("listing printer-drivers\n"); + + for (i=0; archi_table[i].long_archi!=NULL; i++) { + + int num_drivers; + + /* enum remote drivers */ + if (!net_spoolss_enumprinterdrivers(cli, mem_ctx, level, + archi_table[i].long_archi, + &num_drivers, &drv_ctr_enum)) { + + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (num_drivers == 0) { + d_printf ("no drivers found on server for architecture: [%s].\n", + archi_table[i].long_archi); + continue; + } + + d_printf("got %d printer-drivers for architecture: [%s]\n", + num_drivers, archi_table[i].long_archi); + + + /* do something for all drivers for architecture */ + for (d = 0; d < num_drivers; d++) { + display_print_driver_3(&(drv_ctr_enum.info3[d])); + } + } + + nt_status = NT_STATUS_OK; + +done: + return nt_status; + +} + + +/** + * Migrate Printer-ACLs from a source server to the destination server + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passed through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS rpc_printer_migrate_security_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + /* TODO: what now, info2 or info3 ? + convince jerry that we should add clientside setacls level 3 at least + */ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + uint32 i = 0; + uint32 num_printers; + uint32 level = 2; + fstring servername = ""; + pstring printername = "", sharename = ""; + BOOL got_hnd_src = False; + BOOL got_hnd_dst = False; + BOOL got_dst_spoolss_pipe = False; + POLICY_HND hnd_src, hnd_dst; + PRINTER_INFO_CTR ctr_src, ctr_dst, ctr_enum; + struct cli_state *cli_dst = NULL; + + ZERO_STRUCT(ctr_src); + + DEBUG(3,("copying printer ACLs\n")); + + /* connect destination PI_SPOOLSS */ + nt_status = connect_pipe(&cli_dst, PI_SPOOLSS, &got_dst_spoolss_pipe); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + + /* enum source printers */ + if (!get_printer_info(cli, mem_ctx, level, argc, argv, &num_printers, &ctr_enum)) { + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (!num_printers) { + printf ("no printers found on server.\n"); + nt_status = NT_STATUS_OK; + goto done; + } + + + /* do something for all printers */ + for (i = 0; i < num_printers; i++) { + + /* do some initialization */ + rpcstr_pull(printername, ctr_enum.printers_2[i].printername.buffer, + sizeof(printername), -1, STR_TERMINATE); + rpcstr_pull(sharename, ctr_enum.printers_2[i].sharename.buffer, + sizeof(sharename), -1, STR_TERMINATE); + /* we can reset NT_STATUS here because we do not + get any real NT_STATUS-codes anymore from now on */ + nt_status = NT_STATUS_UNSUCCESSFUL; + + d_printf("migrating printer ACLs for: [%s] / [%s]\n", + printername, sharename); + + /* according to msdn you have specify these access-rights + to see the security descriptor + - READ_CONTROL (DACL) + - ACCESS_SYSTEM_SECURITY (SACL) + */ + + /* open src printer handle */ + if (!net_spoolss_open_printer_ex(cli, mem_ctx, sharename, "", + MAXIMUM_ALLOWED_ACCESS, servername, cli->user_name, &hnd_src)) + goto done; + + got_hnd_src = True; + + + /* open dst printer handle */ + if (!net_spoolss_open_printer_ex(cli_dst, mem_ctx, sharename, "", + PRINTER_ALL_ACCESS, servername, cli_dst->user_name, &hnd_dst)) + goto done; + + got_hnd_dst = True; + + + /* check for existing dst printer */ + if (!net_spoolss_getprinter(cli_dst, mem_ctx, &hnd_dst, level, &ctr_dst)) + goto done; + + /* check for existing src printer */ + if (!net_spoolss_getprinter(cli, mem_ctx, &hnd_src, 3, &ctr_src)) + goto done; + + + /* Copy Security Descriptor */ + + /* copy secdesc (info level 2) */ + ctr_dst.printers_2->devmode = NULL; + ctr_dst.printers_2->secdesc = dup_sec_desc(mem_ctx, ctr_src.printers_3->secdesc); + + if (opt_verbose) + display_sec_desc(ctr_dst.printers_2->secdesc); + + if (!net_spoolss_setprinter(cli_dst, mem_ctx, &hnd_dst, 2, &ctr_dst)) + goto done; + + DEBUGADD(1,("\tSetPrinter of SECDESC succeeded\n")); + + + /* close printer handles here */ + if (got_hnd_src) { + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + got_hnd_src = False; + } + + if (got_hnd_dst) { + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + got_hnd_dst = False; + } + + } + + nt_status = NT_STATUS_OK; + +done: + + if (got_hnd_src) + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + + if (got_hnd_dst) + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + + if (got_dst_spoolss_pipe) { + cli_nt_session_close(cli_dst); + cli_shutdown(cli_dst); + } + return nt_status; +} + + +/** + * Migrate printer-forms from a src server to the dst server + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passed through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS rpc_printer_migrate_forms_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + WERROR result; + uint32 i, f; + uint32 num_printers; + uint32 level = 1; + fstring servername = ""; + pstring printername = "", sharename = ""; + BOOL got_hnd_src = False; + BOOL got_hnd_dst = False; + BOOL got_dst_spoolss_pipe = False; + POLICY_HND hnd_src, hnd_dst; + PRINTER_INFO_CTR ctr_enum, ctr_dst; + uint32 num_forms; + FORM_1 *forms; + struct cli_state *cli_dst = NULL; + + ZERO_STRUCT(ctr_enum); + + DEBUG(3,("copying forms\n")); + + /* connect destination PI_SPOOLSS */ + nt_status = connect_pipe(&cli_dst, PI_SPOOLSS, &got_dst_spoolss_pipe); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + + /* enum src printers */ + if (!get_printer_info(cli, mem_ctx, 2, argc, argv, &num_printers, &ctr_enum)) { + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (!num_printers) { + printf ("no printers found on server.\n"); + nt_status = NT_STATUS_OK; + goto done; + } + + + /* do something for all printers */ + for (i = 0; i < num_printers; i++) { + + /* do some initialization */ + rpcstr_pull(printername, ctr_enum.printers_2[i].printername.buffer, + sizeof(printername), -1, STR_TERMINATE); + rpcstr_pull(sharename, ctr_enum.printers_2[i].sharename.buffer, + sizeof(sharename), -1, STR_TERMINATE); + /* we can reset NT_STATUS here because we do not + get any real NT_STATUS-codes anymore from now on */ + nt_status = NT_STATUS_UNSUCCESSFUL; + + d_printf("migrating printer forms for: [%s] / [%s]\n", + printername, sharename); + + + /* open src printer handle */ + if (!net_spoolss_open_printer_ex(cli, mem_ctx, sharename, "", + MAXIMUM_ALLOWED_ACCESS, servername, cli->user_name, &hnd_src)) + goto done; + + got_hnd_src = True; + + + /* open dst printer handle */ + if (!net_spoolss_open_printer_ex(cli_dst, mem_ctx, sharename, "", + PRINTER_ALL_ACCESS, servername, cli->user_name, &hnd_dst)) + goto done; + + got_hnd_dst = True; + + + /* check for existing dst printer */ + if (!net_spoolss_getprinter(cli_dst, mem_ctx, &hnd_dst, level, &ctr_dst)) + goto done; + + /* finally migrate forms */ + if (!net_spoolss_enumforms(cli, mem_ctx, &hnd_src, level, &num_forms, &forms)) + goto done; + + DEBUG(1,("got %d forms for printer\n", num_forms)); + + + for (f = 0; f < num_forms; f++) { + + FORM form; + fstring form_name; + + /* only migrate FORM_PRINTER types, according to jerry + FORM_BUILTIN-types are hard-coded in samba */ + if (forms[f].flag != FORM_PRINTER) + continue; + + if (forms[f].name.buffer) + rpcstr_pull(form_name, forms[f].name.buffer, + sizeof(form_name), -1, STR_TERMINATE); + + if (opt_verbose) + d_printf("\tmigrating form # %d [%s] of type [%d]\n", + f, form_name, forms[f].flag); + + /* is there a more elegant way to do that ? */ + form.flags = FORM_PRINTER; + form.size_x = forms[f].width; + form.size_y = forms[f].length; + form.left = forms[f].left; + form.top = forms[f].top; + form.right = forms[f].right; + form.bottom = forms[f].bottom; + + init_unistr2(&form.name, form_name, UNI_STR_TERMINATE); + + /* FIXME: there might be something wrong with samba's + builtin-forms */ + result = cli_spoolss_addform(cli_dst, mem_ctx, + &hnd_dst, 1, &form); + if (!W_ERROR_IS_OK(result)) { + d_printf("\tAddForm form %d: [%s] refused.\n", + f, form_name); + continue; + } + + DEBUGADD(1,("\tAddForm of [%s] succeeded\n", form_name)); + } + + + /* close printer handles here */ + if (got_hnd_src) { + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + got_hnd_src = False; + } + + if (got_hnd_dst) { + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + got_hnd_dst = False; + } + } + + nt_status = NT_STATUS_OK; + +done: + + if (got_hnd_src) + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + + if (got_hnd_dst) + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + + if (got_dst_spoolss_pipe) { + cli_nt_session_close(cli_dst); + cli_shutdown(cli_dst); + } + return nt_status; + +} + + +/** + * Migrate printer-drivers from a src server to the dst server + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passed through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS rpc_printer_migrate_drivers_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + uint32 i, p; + uint32 num_printers; + uint32 level = 3; + fstring servername = ""; + pstring printername = "", sharename = ""; + BOOL got_hnd_src = False; + BOOL got_hnd_dst = False; + BOOL got_dst_spoolss_pipe = False; + BOOL got_src_driver_share = False; + BOOL got_dst_driver_share = False; + POLICY_HND hnd_src, hnd_dst; + PRINTER_DRIVER_CTR drv_ctr_src, drv_ctr_dst; + PRINTER_INFO_CTR info_ctr_enum, info_ctr_dst; + struct cli_state *cli_dst = NULL; + struct cli_state *cli_share_src = NULL; + struct cli_state *cli_share_dst = NULL; + fstring drivername = ""; + + ZERO_STRUCT(drv_ctr_src); + ZERO_STRUCT(drv_ctr_dst); + ZERO_STRUCT(info_ctr_enum); + ZERO_STRUCT(info_ctr_dst); + + + DEBUG(3,("copying printer-drivers\n")); + + nt_status = connect_pipe(&cli_dst, PI_SPOOLSS, &got_dst_spoolss_pipe); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + + /* open print$-share on the src server */ + nt_status = connect_to_service(&cli_share_src, &cli->dest_ip, + cli->desthost, "print$", "A:"); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + got_src_driver_share = True; + + + /* open print$-share on the dst server */ + nt_status = connect_to_service(&cli_share_dst, &cli_dst->dest_ip, + cli_dst->desthost, "print$", "A:"); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + got_dst_driver_share = True; + + + /* enum src printers */ + if (!get_printer_info(cli, mem_ctx, 2, argc, argv, &num_printers, &info_ctr_enum)) { + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (!num_printers) { + printf ("no printers found on server.\n"); + nt_status = NT_STATUS_OK; + goto done; + } + + + /* do something for all printers */ + for (p = 0; p < num_printers; p++) { + + /* do some initialization */ + rpcstr_pull(printername, info_ctr_enum.printers_2[p].printername.buffer, + sizeof(printername), -1, STR_TERMINATE); + rpcstr_pull(sharename, info_ctr_enum.printers_2[p].sharename.buffer, + sizeof(sharename), -1, STR_TERMINATE); + /* we can reset NT_STATUS here because we do not + get any real NT_STATUS-codes anymore from now on */ + nt_status = NT_STATUS_UNSUCCESSFUL; + + d_printf("migrating printer driver for: [%s] / [%s]\n", + printername, sharename); + + /* open dst printer handle */ + if (!net_spoolss_open_printer_ex(cli_dst, mem_ctx, sharename, "", + PRINTER_ALL_ACCESS, servername, cli->user_name, &hnd_dst)) + goto done; + + got_hnd_dst = True; + + /* check for existing dst printer */ + if (!net_spoolss_getprinter(cli_dst, mem_ctx, &hnd_dst, 2, &info_ctr_dst)) + goto done; + + + /* open src printer handle */ + if (!net_spoolss_open_printer_ex(cli, mem_ctx, sharename, "", + MAXIMUM_ALLOWED_ACCESS, servername, cli->user_name, &hnd_src)) + goto done; + + got_hnd_src = True; + + + /* in a first step call getdriver for each shared printer (per arch) + to get a list of all files that have to be copied */ + + for (i=0; archi_table[i].long_archi!=NULL; i++) { + + /* getdriver src */ + if (!net_spoolss_getprinterdriver(cli, mem_ctx, &hnd_src, + level, archi_table[i].long_archi, + archi_table[i].version, &drv_ctr_src)) + continue; + + rpcstr_pull(drivername, drv_ctr_src.info3->name.buffer, + sizeof(drivername), -1, STR_TERMINATE); + + if (opt_verbose) + display_print_driver_3(drv_ctr_src.info3); + + + /* check arch dir */ + nt_status = check_arch_dir(cli_share_dst, archi_table[i].short_archi); + if (!NT_STATUS_IS_OK(nt_status)) + goto done; + + + /* copy driver-files */ + nt_status = copy_print_driver_3(mem_ctx, cli_share_src, cli_share_dst, + archi_table[i].short_archi, + drv_ctr_src.info3); + if (!NT_STATUS_IS_OK(nt_status)) + goto done; + + + /* adddriver dst */ + if (!net_spoolss_addprinterdriver(cli_dst, mem_ctx, level, &drv_ctr_src)) { + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + DEBUGADD(1,("Sucessfully added driver [%s] for printer [%s]\n", + drivername, printername)); + + } + + /* setdriver dst */ + init_unistr(&info_ctr_dst.printers_2->drivername, drivername); + + if (!net_spoolss_setprinter(cli_dst, mem_ctx, &hnd_dst, 2, &info_ctr_dst)) { + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + DEBUGADD(1,("Sucessfully set driver %s for printer %s\n", + drivername, printername)); + + /* close dst */ + if (got_hnd_dst) { + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + got_hnd_dst = False; + } + + /* close src */ + if (got_hnd_src) { + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + got_hnd_src = False; + } + } + + nt_status = NT_STATUS_OK; + +done: + + if (got_hnd_src) + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + + if (got_hnd_dst) + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + + if (got_dst_spoolss_pipe) { + cli_nt_session_close(cli_dst); + cli_shutdown(cli_dst); + } + + if (got_src_driver_share) + cli_shutdown(cli_share_src); + + if (got_dst_driver_share) + cli_shutdown(cli_share_dst); + + return nt_status; + +} + + +/** + * Migrate printer-queues from a src to the dst server + * (requires a working "addprinter command" to be installed for the local smbd) + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passed through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS rpc_printer_migrate_printers_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + uint32 i = 0, num_printers; + uint32 level = 2; + PRINTER_INFO_CTR ctr_src, ctr_dst, ctr_enum; + struct cli_state *cli_dst = NULL; + POLICY_HND hnd_dst, hnd_src; + pstring printername, sharename; + fstring servername; + BOOL got_hnd_src = False; + BOOL got_hnd_dst = False; + BOOL got_dst_spoolss_pipe = False; + + DEBUG(3,("copying printers\n")); + + /* connect destination PI_SPOOLSS */ + nt_status = connect_pipe(&cli_dst, PI_SPOOLSS, &got_dst_spoolss_pipe); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + + /* enum printers */ + if (!get_printer_info(cli, mem_ctx, 2, argc, argv, &num_printers, &ctr_enum)) { + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (!num_printers) { + printf ("no printers found on server.\n"); + nt_status = NT_STATUS_OK; + goto done; + } + + + /* do something for all printers */ + for (i = 0; i < num_printers; i++) { + + /* do some initialization */ + rpcstr_pull(printername, ctr_enum.printers_2[i].printername.buffer, + sizeof(printername), -1, STR_TERMINATE); + rpcstr_pull(sharename, ctr_enum.printers_2[i].sharename.buffer, + sizeof(sharename), -1, STR_TERMINATE); + /* we can reset NT_STATUS here because we do not + get any real NT_STATUS-codes anymore from now on */ + nt_status = NT_STATUS_UNSUCCESSFUL; + + d_printf("migrating printer queue for: [%s] / [%s]\n", + printername, sharename); + + + /* open dst printer handle */ + if (!net_spoolss_open_printer_ex(cli_dst, mem_ctx, sharename, "", + PRINTER_ALL_ACCESS, servername, cli->user_name, &hnd_dst)) { + + DEBUG(1,("could not open printer: %s\n", sharename)); + } else { + got_hnd_dst = True; + } + + + /* check for existing dst printer */ + if (!net_spoolss_getprinter(cli_dst, mem_ctx, &hnd_dst, level, &ctr_dst)) { + printf ("could not get printer, creating printer.\n"); + } else { + DEBUG(1,("printer already exists: %s\n", sharename)); + /* close printer handles here */ + if (got_hnd_src) { + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + got_hnd_src = False; + } + + if (got_hnd_dst) { + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + got_hnd_dst = False; + } + continue; + } + + + /* now get again src printer ctr via getprinter, + we first need a handle for that */ + + /* open src printer handle */ + if (!net_spoolss_open_printer_ex(cli, mem_ctx, sharename, "", + MAXIMUM_ALLOWED_ACCESS, servername, cli->user_name, &hnd_src)) + goto done; + + got_hnd_src = True; + + /* getprinter on the src server */ + if (!net_spoolss_getprinter(cli, mem_ctx, &hnd_src, level, &ctr_src)) + goto done; + + + /* copy each src printer to a dst printer 1:1, + maybe some values have to be changed though */ + d_printf("creating printer: %s\n", printername); + result = cli_spoolss_addprinterex (cli_dst, mem_ctx, level, &ctr_src); + + if (W_ERROR_IS_OK(result)) + d_printf ("printer [%s] successfully added.\n", printername); + else if (W_ERROR_V(result) == W_ERROR_V(WERR_PRINTER_ALREADY_EXISTS)) + d_printf ("printer [%s] already exists.\n", printername); + else { + printf ("could not create printer\n"); + goto done; + } + + /* close printer handles here */ + if (got_hnd_src) { + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + got_hnd_src = False; + } + + if (got_hnd_dst) { + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + got_hnd_dst = False; + } + } + + nt_status = NT_STATUS_OK; + +done: + if (got_hnd_src) + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + + if (got_hnd_dst) + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + + if (got_dst_spoolss_pipe) { + cli_nt_session_close(cli_dst); + cli_shutdown(cli_dst); + } + return nt_status; +} + + +/** + * Migrate Printer-Settings from a src server to the dst server + * (for this to work, printers and drivers already have to be migrated earlier) + * + * All parameters are provided by the run_rpc_command function, except for + * argc, argv which are passed through. + * + * @param domain_sid The domain sid aquired from the remote server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param argc Standard main() style argc + * @param argv Standard main() style argv. Initial components are already + * stripped + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS rpc_printer_migrate_settings_internals(const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + + /* FIXME: Here the nightmare begins */ + + WERROR result; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + uint32 i = 0, p = 0, j = 0; + uint32 num_printers, val_needed, data_needed; + uint32 level = 2; + fstring servername = ""; + pstring printername = "", sharename = ""; + BOOL got_hnd_src = False; + BOOL got_hnd_dst = False; + BOOL got_dst_spoolss_pipe = False; + POLICY_HND hnd_src, hnd_dst; + PRINTER_INFO_CTR ctr_enum, ctr_dst, ctr_dst_publish; + REGVAL_CTR reg_ctr; + struct cli_state *cli_dst = NULL; + char *devicename = NULL, *unc_name = NULL, *url = NULL; + fstring longname; + + const char *keyname = NULL; + uint16 *keylist = NULL, *curkey; + + ZERO_STRUCT(ctr_enum); + + DEBUG(3,("copying printer settings\n")); + + /* connect destination PI_SPOOLSS */ + nt_status = connect_pipe(&cli_dst, PI_SPOOLSS, &got_dst_spoolss_pipe); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + + /* enum src printers */ + if (!get_printer_info(cli, mem_ctx, level, argc, argv, &num_printers, &ctr_enum)) { + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (!num_printers) { + printf ("no printers found on server.\n"); + nt_status = NT_STATUS_OK; + goto done; + } + + + /* needed for dns-strings in regkeys */ + get_mydnsfullname(longname); + + /* do something for all printers */ + for (i = 0; i < num_printers; i++) { + + /* do some initialization */ + rpcstr_pull(printername, ctr_enum.printers_2[i].printername.buffer, + sizeof(printername), -1, STR_TERMINATE); + rpcstr_pull(sharename, ctr_enum.printers_2[i].sharename.buffer, + sizeof(sharename), -1, STR_TERMINATE); + keyname = ""; + /* we can reset NT_STATUS here because we do not + get any real NT_STATUS-codes anymore from now on */ + nt_status = NT_STATUS_UNSUCCESSFUL; + + d_printf("migrating printer settings for: [%s] / [%s]\n", + printername, sharename); + + + /* open src printer handle */ + if (!net_spoolss_open_printer_ex(cli, mem_ctx, sharename, "", + MAXIMUM_ALLOWED_ACCESS, servername, cli->user_name, &hnd_src)) + goto done; + + got_hnd_src = True; + + + /* open dst printer handle */ + if (!net_spoolss_open_printer_ex(cli_dst, mem_ctx, sharename, "", + PRINTER_ALL_ACCESS, servername, cli_dst->user_name, &hnd_dst)) + goto done; + + got_hnd_dst = True; + + + /* check for existing dst printer */ + if (!net_spoolss_getprinter(cli_dst, mem_ctx, &hnd_dst, + level, &ctr_dst)) + goto done; + + + /* STEP 1: COPY DEVICE-MODE and other + PRINTER_INFO_2-attributes + */ + + ctr_dst.printers_2 = &ctr_enum.printers_2[i]; + + /* why is the port always disconnected when the printer + is correctly installed (incl. driver ???) */ + init_unistr( &ctr_dst.printers_2->portname, SAMBA_PRINTER_PORT_NAME); + + /* check if printer is published */ + if (ctr_enum.printers_2[i].attributes & PRINTER_ATTRIBUTE_PUBLISHED) { + + /* check for existing dst printer */ + if (!net_spoolss_getprinter(cli_dst, mem_ctx, &hnd_dst, 7, &ctr_dst_publish)) + goto done; + + ctr_dst_publish.printers_7->action = SPOOL_DS_PUBLISH; + + /* ignore False from setprinter due to WERR_IO_PENDING */ + net_spoolss_setprinter(cli_dst, mem_ctx, &hnd_dst, 7, &ctr_dst_publish); + + DEBUG(3,("republished printer\n")); + } + + /* copy devmode (info level 2) */ + ctr_dst.printers_2->devmode = talloc_memdup(mem_ctx, + ctr_enum.printers_2[i].devmode, sizeof(DEVICEMODE)); + + /* do not copy security descriptor (we have another command for that) */ + ctr_dst.printers_2->secdesc = NULL; + + + /* devmode->devicename is possibly broken at the moment for all + strlen(longprinternames) > MAXDEVICENAME (that is 32 chars) + this fires up thousands of safe_strncpy-debug0-messages + on my test-servers + TODO: tell jerry, jra, etc. again. + */ + +#if 0 + if (asprintf(&devicename, "\\\\%s\\%s", longname, printername) < 0) { + nt_status = NT_STATUS_NO_MEMORY; + goto done; + } + + init_unistr(&ctr_dst.printers_2->devmode->devicename, devicename); +#endif + if (!net_spoolss_setprinter(cli_dst, mem_ctx, &hnd_dst, + level, &ctr_dst)) + goto done; + + DEBUGADD(1,("\tSetPrinter of DEVICEMODE succeeded\n")); + + + + /* STEP 2: COPY REGISTRY VALUES */ + + /* please keep in mind that samba parse_spools gives horribly + crippled results when used to cli_spoolss_enumprinterdataex + a win2k3-server. + FIXME: IIRC I've seen it too on a win2k-server + */ + + /* enumerate data on src handle */ + result = cli_spoolss_enumprinterdata(cli, mem_ctx, &hnd_src, p, 0, 0, + &val_needed, &data_needed, NULL); + + /* loop for all printerdata */ + while (W_ERROR_IS_OK(result)) { + + REGISTRY_VALUE value; + + result = cli_spoolss_enumprinterdata( + cli, mem_ctx, &hnd_src, p++, val_needed, + data_needed, 0, 0, &value); + + /* loop for all reg_keys */ + if (W_ERROR_IS_OK(result)) { + + /* display_value */ + if (opt_verbose) + display_reg_value(NULL, value); + + /* set_value */ + if (!net_spoolss_setprinterdata(cli_dst, mem_ctx, + &hnd_dst, &value)) + goto done; + + DEBUGADD(1,("\tSetPrinterData of [%s] succeeded\n", + value.valuename)); + } + } + + /* STEP 3: COPY SUBKEY VALUES */ + + /* here we need to enum all printer_keys and then work + on the result with enum_printer_key_ex. nt4 does not + respond to enumprinterkey, win2k does, so continue + in case of an error */ + + if (!net_spoolss_enumprinterkey(cli, mem_ctx, &hnd_src, keyname, &keylist)) { + printf("got no key-data\n"); + continue; + } + + + /* work on a list of printer keys + each key has to be enumerated to get all required + information. information is then set via setprinterdataex-calls */ + + if (keylist == NULL) + continue; + + curkey = keylist; + while (*curkey != 0) { + + pstring subkey; + rpcstr_pull(subkey, curkey, sizeof(subkey), -1, STR_TERMINATE); + + curkey += strlen(subkey) + 1; + + /* enumerate all src subkeys */ + if (!net_spoolss_enumprinterdataex(cli, mem_ctx, 0, + &hnd_src, subkey, + ®_ctr)) + goto done; + + for (j=0; j < reg_ctr.num_values; j++) { + + REGISTRY_VALUE value; + UNISTR2 data; + + /* although samba replies with sane data in most cases we + should try to avoid writing wrong registry data */ + + if (strequal(reg_ctr.values[j]->valuename, SPOOL_REG_PORTNAME) || + strequal(reg_ctr.values[j]->valuename, SPOOL_REG_UNCNAME) || + strequal(reg_ctr.values[j]->valuename, SPOOL_REG_URL) || + strequal(reg_ctr.values[j]->valuename, SPOOL_REG_SHORTSERVERNAME) || + strequal(reg_ctr.values[j]->valuename, SPOOL_REG_SERVERNAME)) { + + if (strequal(reg_ctr.values[j]->valuename, SPOOL_REG_PORTNAME)) { + + /* although windows uses a multi-sz, we use a sz */ + init_unistr2(&data, SAMBA_PRINTER_PORT_NAME, UNI_STR_TERMINATE); + fstrcpy(value.valuename, SPOOL_REG_PORTNAME); + } + + if (strequal(reg_ctr.values[j]->valuename, SPOOL_REG_UNCNAME)) { + + if (asprintf(&unc_name, "\\\\%s\\%s", longname, sharename) < 0) { + nt_status = NT_STATUS_NO_MEMORY; + goto done; + } + init_unistr2(&data, unc_name, UNI_STR_TERMINATE); + fstrcpy(value.valuename, SPOOL_REG_UNCNAME); + } + + if (strequal(reg_ctr.values[j]->valuename, SPOOL_REG_URL)) { + + continue; + +#if 0 + /* FIXME: should we really do that ??? */ + if (asprintf(&url, "http://%s:631/printers/%s", longname, sharename) < 0) { + nt_status = NT_STATUS_NO_MEMORY; + goto done; + } + init_unistr2(&data, url, UNI_STR_TERMINATE); + fstrcpy(value.valuename, SPOOL_REG_URL); +#endif + } + + if (strequal(reg_ctr.values[j]->valuename, SPOOL_REG_SERVERNAME)) { + + init_unistr2(&data, longname, UNI_STR_TERMINATE); + fstrcpy(value.valuename, SPOOL_REG_SERVERNAME); + } + + if (strequal(reg_ctr.values[j]->valuename, SPOOL_REG_SHORTSERVERNAME)) { + + init_unistr2(&data, global_myname(), UNI_STR_TERMINATE); + fstrcpy(value.valuename, SPOOL_REG_SHORTSERVERNAME); + } + + value.type = REG_SZ; + value.size = data.uni_str_len * 2; + value.data_p = talloc_memdup(mem_ctx, data.buffer, value.size); + + if (opt_verbose) + display_reg_value(subkey, value); + + /* here we have to set all subkeys on the dst server */ + if (!net_spoolss_setprinterdataex(cli_dst, mem_ctx, &hnd_dst, + subkey, &value)) + goto done; + + } else { + + if (opt_verbose) + display_reg_value(subkey, *(reg_ctr.values[j])); + + /* here we have to set all subkeys on the dst server */ + if (!net_spoolss_setprinterdataex(cli_dst, mem_ctx, &hnd_dst, + subkey, reg_ctr.values[j])) + goto done; + + } + + DEBUGADD(1,("\tSetPrinterDataEx of key [%s\\%s] succeeded\n", + subkey, reg_ctr.values[j]->valuename)); + + } + + regval_ctr_destroy(®_ctr); + } + + safe_free(keylist); + + /* close printer handles here */ + if (got_hnd_src) { + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + got_hnd_src = False; + } + + if (got_hnd_dst) { + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + got_hnd_dst = False; + } + + } + + nt_status = NT_STATUS_OK; + +done: + SAFE_FREE(devicename); + SAFE_FREE(url); + SAFE_FREE(unc_name); + + if (got_hnd_src) + cli_spoolss_close_printer(cli, mem_ctx, &hnd_src); + + if (got_hnd_dst) + cli_spoolss_close_printer(cli_dst, mem_ctx, &hnd_dst); + + if (got_dst_spoolss_pipe) { + cli_nt_session_close(cli_dst); + cli_shutdown(cli_dst); + } + return nt_status; +} diff --git a/source/utils/smbcacls.c b/source/utils/smbcacls.c index cb82ad831eb..4dc89aecb9d 100644 --- a/source/utils/smbcacls.c +++ b/source/utils/smbcacls.c @@ -761,11 +761,13 @@ static struct cli_state *connect_one(const char *share) ctx=talloc_init("main"); - setlinebuf(stdout); - + /* set default debug level to 0 regardless of what smb.conf sets */ + setup_logging( "smbcacls", True ); + DEBUGLEVEL_CLASS[DBGC_ALL] = 1; dbf = x_stderr; + x_setbuf( x_stderr, NULL ); - setup_logging(argv[0],True); + setlinebuf(stdout); lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); diff --git a/source/utils/smbcquotas.c b/source/utils/smbcquotas.c index 0bd87554209..81f7dd42bbc 100644 --- a/source/utils/smbcquotas.c +++ b/source/utils/smbcquotas.c @@ -236,8 +236,9 @@ static int do_quota(struct cli_state *cli, enum SMB_QUOTA_TYPE qtype, uint16 cmd } if (!cli_get_quota_handle(cli, "a_fnum)) { - d_printf("Failed to open \\%s %s.\n", - FAKE_FILE_NAME_QUOTA,cli_errstr(cli)); + d_printf("Quotas are not enabled on this share.\n"); + d_printf("Failed to open %s %s.\n", + FAKE_FILE_NAME_QUOTA_WIN32,cli_errstr(cli)); return -1; } @@ -419,14 +420,15 @@ FSQFLAGS:QUOTA_ENABLED/DENY_DISK/LOG_SOFTLIMIT/LOG_HARD_LIMIT", "SETSTRING" }, ZERO_STRUCT(qt); - setlinebuf(stdout); - + /* set default debug level to 1 regardless of what smb.conf sets */ + setup_logging( "smbcquotas", True ); + DEBUGLEVEL_CLASS[DBGC_ALL] = 1; dbf = x_stderr; + x_setbuf( x_stderr, NULL ); - fault_setup(NULL); - - setup_logging(argv[0],True); + setlinebuf(stdout); + fault_setup(NULL); lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); |