From 0c9adb69858c7572320d18c0fd187dd6e885f17d Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Tue, 13 Jan 2004 17:55:43 +0000 Subject: sync HEAD with recent changes in 3.0 (This used to be commit c98399e3c9d74e19b7c9d806ca8028b48866931e) --- source3/Makefile.in | 26 +- source3/auth/auth_domain.c | 4 +- source3/bin/.cvsignore | 6 +- source3/client/mount.cifs.c | 680 ++++++++++++++++++++++----------- source3/configure.in | 101 +++-- source3/include/printing.h | 2 - source3/include/samba_linux_quota.h | 336 ++++++++++++++++ source3/include/samba_xfs_quota.h | 165 ++++++++ source3/include/sysquotas.h | 152 +------- source3/intl/lang_tdb.c | 3 +- source3/lib/charcnv.c | 4 +- source3/lib/sysquotas.c | 529 ------------------------- source3/lib/sysquotas_4A.c | 318 +++++++++++++++ source3/lib/sysquotas_linux.c | 485 +++++++++++++++++++++++ source3/lib/sysquotas_xfs.c | 306 +++++++++++++++ source3/lib/talloctort.c | 4 +- source3/lib/time.c | 5 +- source3/lib/util_str.c | 6 +- source3/libads/sasl.c | 17 +- source3/libsmb/cliconnect.c | 46 ++- source3/libsmb/clikrb5.c | 24 +- source3/libsmb/clispnego.c | 17 +- source3/libsmb/namequery.c | 86 +++-- source3/locking/locking.c | 4 +- source3/nmbd/nmbd_processlogon.c | 2 +- source3/nsswitch/wbinfo.c | 26 +- source3/nsswitch/winbind_nss_freebsd.c | 81 ++++ source3/nsswitch/winbindd.c | 2 + source3/nsswitch/winbindd.h | 3 +- source3/nsswitch/winbindd_ads.c | 2 +- source3/nsswitch/winbindd_cache.c | 6 +- source3/nsswitch/winbindd_cm.c | 103 ++++- source3/nsswitch/winbindd_group.c | 62 ++- source3/nsswitch/winbindd_misc.c | 16 +- source3/nsswitch/winbindd_nss.h | 3 +- source3/nsswitch/winbindd_rpc.c | 13 +- source3/nsswitch/winbindd_sid.c | 8 +- source3/nsswitch/winbindd_user.c | 52 ++- source3/nsswitch/winbindd_util.c | 45 ++- source3/nsswitch/wins.c | 4 +- source3/param/loadparm.c | 18 +- source3/passdb/secrets.c | 38 ++ source3/printing/notify.c | 1 + source3/printing/print_cups.c | 1 + source3/printing/print_generic.c | 1 + source3/printing/printing.c | 1 + source3/printing/printing_db.c | 1 + source3/rpc_client/cli_lsarpc.c | 89 +++-- source3/rpc_server/srv_samr_nt.c | 17 +- source3/rpcclient/cmd_lsarpc.c | 30 +- source3/rpcclient/cmd_spoolss.c | 2 +- source3/script/installswat.sh | 2 +- source3/script/mkbuildoptions.awk | 16 +- source3/smbd/chgpasswd.c | 81 ++-- source3/smbd/quotas.c | 159 +++++--- source3/tdb/tdb.c | 2 + source3/tests/crack.c | 5 + source3/utils/net_rpc.c | 40 +- source3/utils/ntlm_auth.c | 15 +- source3/utils/smbcontrol.c | 2 +- source3/utils/smbget.c | 574 ++++++++++++++++++++++++++++ 61 files changed, 3485 insertions(+), 1364 deletions(-) create mode 100644 source3/include/samba_linux_quota.h create mode 100644 source3/include/samba_xfs_quota.h create mode 100644 source3/lib/sysquotas_4A.c create mode 100644 source3/lib/sysquotas_linux.c create mode 100644 source3/lib/sysquotas_xfs.c create mode 100644 source3/nsswitch/winbind_nss_freebsd.c create mode 100644 source3/tests/crack.c create mode 100644 source3/utils/smbget.c (limited to 'source3') diff --git a/source3/Makefile.in b/source3/Makefile.in index 923f4dbd5b..68aead0fc2 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -85,7 +85,6 @@ PRIVATEDIR = @privatedir@ SMB_PASSWD_FILE = $(PRIVATEDIR)/smbpasswd PRIVATE_DIR = $(PRIVATEDIR) -DATADIR = @datadir@ # This is where SWAT images and help files go SWATDIR = @swatdir@ @@ -202,11 +201,11 @@ UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \ PARAM_OBJ = dynconfig.o param/loadparm.o param/params.o param/modconf.o -KRBCLIENT_OBJ = libads/kerberos.o +KRBCLIENT_OBJ = libads/kerberos.o libads/ads_status.o LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o libads/sasl.o \ libads/krb5_setpw.o libads/ldap_user.o \ - libads/ads_struct.o libads/ads_status.o \ + libads/ads_struct.o \ libads/disp_sec.o libads/ads_utils.o libads/ldap_utils.o \ libads/ads_ldap.o libads/authdata.o @@ -362,8 +361,9 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \ smbd/vfs.o smbd/vfs-wrap.o smbd/statcache.o \ smbd/posix_acls.o lib/sysacls.o lib/server_mutex.o \ smbd/process.o smbd/service.o smbd/error.o \ - printing/printfsp.o \ - lib/sysquotas.o smbd/change_trust_pw.o smbd/fake_file.o \ + printing/printfsp.o lib/sysquotas.o lib/sysquotas_linux.o \ + lib/sysquotas_xfs.o lib/sysquotas_4A.o \ + smbd/change_trust_pw.o smbd/fake_file.o \ smbd/quotas.o smbd/ntquotas.o lib/afs.o \ $(MANGLE_OBJ) @VFS_STATIC@ @@ -450,6 +450,8 @@ PDBEDIT_OBJ = utils/pdbedit.o $(PARAM_OBJ) $(PASSDB_OBJ) $(LIBSAMBA_OBJ) \ $(UBIQX_OBJ) $(LIB_OBJ) $(GROUPDB_OBJ) $(SECRETS_OBJ) \ $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) lib/dummyroot.o +SMBGET_OBJ = utils/smbget.o $(POPT_LIB_OBJ) $(LIBSMBCLIENT_OBJ) $(SECRETS_OBJ) + RPCCLIENT_OBJ1 = rpcclient/rpcclient.o rpcclient/cmd_lsarpc.o \ rpcclient/cmd_samr.o rpcclient/cmd_spoolss.o \ rpcclient/cmd_netlogon.o rpcclient/cmd_srvsvc.o \ @@ -730,6 +732,12 @@ MAKEDIR = || exec false; \ -o $@ @BROKEN_CC@ -mv `echo $@ | sed 's%^.*/%%g'` $@ +# this adds support for precompiled headers. To use it, install a snapshot +# of gcc-3.4 and run 'make pch' before you do the main build. +pch: + rm -f $(srcdir)/include/includes.h.gch + $(CC) -I. -I$(srcdir) $(FLAGS) -c $(srcdir)/include/includes.h -o $(srcdir)/include/includes.h.gch + # These dependencies are only approximately correct: we want to make # sure Samba's paths are updated if ./configure is re-run. Really it # would be nice if "make prefix=/opt/samba all" also rebuilt things, @@ -746,7 +754,7 @@ dynconfig.@PICSUFFIX@: dynconfig.c Makefile @echo Compiling $*.c with @PICFLAGS@ @$(CC) -I. -I$(srcdir) $(FLAGS) $(PATH_FLAGS) @PICFLAGS@ -c $< -o $*.@PICSUFFIX@ @BROKEN_CC@ -mv `echo $@ | sed -e 's%^.*/%%g' -e 's%\.@PICSUFFIX@$$%.o%'` $@ -@POBAD_CC@ @mv $*.@PICSUFFIX@.o $@ +@POBAD_CC@ -@mv $*.@PICSUFFIX@.o $@ lib/version.o: lib/version.c include/version.h @echo Compiling $*.c @@ -870,6 +878,10 @@ bin/pdbedit@EXEEXT@: $(PDBEDIT_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) -o $@ $(PDBEDIT_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) @POPTLIBS@ $(PASSDB_LIBS) $(LDAP_LIBS) +bin/smbget@EXEEXT@: $(SMBGET_OBJ) @BUILD_POPT@ bin/.dummy + @echo Linking $@ + @$(CC) $(FLAGS) -o $@ $(SMBGET_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) + bin/samtest@EXEEXT@: $(SAMTEST_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) -o $@ $(SAMTEST_OBJ) $(LDFLAGS) $(TERMLDFLAGS) $(TERMLIBS) $(DYNEXP) $(LIBS) @POPTLIBS@ $(PASSDB_LIBS) $(KRB5LIBS) $(LDAP_LIBS) @@ -1034,7 +1046,7 @@ bin/librpc_epmapper.@SHLIBEXT@: $(RPC_EPMAPPER_OBJ) bin/winbindd@EXEEXT@: $(WINBINDD_OBJ) @BUILD_POPT@ bin/.dummy @echo "Linking $@" - @$(LINK) -o $@ $(WINBINDD_OBJ) $(DYNEXP) $(LIBS) @POPTLIBS@ $(KRB5LIBS) $(LDAP_LIBS) + @$(LINK) -o $@ $(WINBINDD_OBJ) $(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. diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index 31ffd88083..0bf2031a37 100644 --- a/source3/auth/auth_domain.c +++ b/source3/auth/auth_domain.c @@ -33,10 +33,10 @@ extern BOOL global_machine_password_needs_changing; * @param server either a machine name or text IP address to * connect to. * @param setup_creds_as domain account to setup credentials as - * @param sec_chan switch value to distinguish between domain + * @param sec_chan a switch value to distinguish between domain * member and interdomain authentication * @param trust_passwd the trust password to establish the - * credentials + * credentials with. * **/ diff --git a/source3/bin/.cvsignore b/source3/bin/.cvsignore index 013a5ba6c1..aad6091960 100644 --- a/source3/bin/.cvsignore +++ b/source3/bin/.cvsignore @@ -5,6 +5,7 @@ debug2html editreg locktest locktest2 +log2pcap make_printerdef make_smbcodepage make_unicodemap @@ -28,6 +29,7 @@ smbcquotas smbd smbfilter smbgroupedit +smbiconv smbmnt smbmount smbpasswd @@ -37,7 +39,6 @@ smbstatus smbtorture smbtree smbumount -smbiconv swat t_push_ucs2 t_snprintf @@ -45,11 +46,10 @@ t_strcmp t_stringoverflow talloctort tdbbackup +tdbdump testparm testprns vfstest -log2pcap wbinfo winbindd wrepld -tdbdump diff --git a/source3/client/mount.cifs.c b/source3/client/mount.cifs.c index 43b20e9d50..8c23cc2212 100755 --- a/source3/client/mount.cifs.c +++ b/source3/client/mount.cifs.c @@ -1,6 +1,27 @@ +/* + Mount helper utility for Linux CIFS VFS (virtual filesystem) client + Copyright (C) 2003 Steve French (sfrench@us.ibm.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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 _GNU_SOURCE #define _GNU_SOURCE +#endif #include +#include #include #include #include @@ -14,10 +35,14 @@ #include #include #include +#include -#define MOUNT_CIFS_VERSION "1" +#define MOUNT_CIFS_VERSION_MAJOR "1" +#define MOUNT_CIFS_VERSION_MINOR "0" -extern char *getusername(void); +#ifndef MOUNT_CIFS_VENDOR_SUFFIX +#define MOUNT_CIFS_VENDOR_SUFFIX "" +#endif char * thisprogram; int verboseflag = 0; @@ -41,17 +66,20 @@ char * mountpassword = NULL; BB end finish BB */ -void mount_cifs_usage() +static void mount_cifs_usage(void) { - printf("\nUsage: %s remotetarget dir\n", thisprogram); - printf("\nMount the remotetarget, specified as either a UNC name or "); - printf(" CIFS URL, to the local directory, dir.\n"); - + printf("\nUsage: %s -o \n", thisprogram); + printf("\nMount the remote target, specified as a UNC name,"); + printf(" to a local directory.\n"); + if(mountpassword) { + memset(mountpassword,0,64); + free(mountpassword); + } exit(1); } /* caller frees username if necessary */ -char * getusername() { +static char * getusername(void) { char *username = NULL; struct passwd *password = getpwuid(getuid()); @@ -61,25 +89,185 @@ char * getusername() { return username; } -char * parse_cifs_url(unc_name) +char * parse_cifs_url(char * unc_name) { printf("\ncifs url %s\n",unc_name); + return NULL; +} + +static int open_cred_file(char * file_name) +{ + char * line_buf; + char * temp_val; + FILE * fs; + int i, length; + fs = fopen(file_name,"r"); + if(fs == NULL) + return errno; + line_buf = malloc(4096); + if(line_buf == NULL) + return -ENOMEM; + + while(fgets(line_buf,4096,fs)) { + /* parse line from credential file */ + + /* eat leading white space */ + for(i=0;i<4096;i++) { + if(line_buf[i] == '\0') + break; + else if((line_buf[i] != ' ') && (line_buf[i] != '\t')) + break; + line_buf++; + } + + if (strncasecmp("username",line_buf,8) == 0) { + temp_val = strchr(line_buf + i,'='); + if(temp_val) { + /* go past equals sign */ + temp_val++; + length = strlen(temp_val); + if(length > 4086) { + printf("cifs.mount failed due to malformed username in credentials file"); + memset(line_buf,0,4096); + if(mountpassword) { + memset(mountpassword,0,64); + } + exit(1); + } else { + got_user = 1; + user_name = calloc(1 + length,1); + /* BB adding free of user_name string before exit, + not really necessary but would be cleaner */ + strncpy(user_name,temp_val, length); + } + } + } else if (strncasecmp("password",line_buf,8) == 0) { + temp_val = strchr(line_buf+i,'='); + if(temp_val) { + /* go past equals sign */ + temp_val++; + length = strlen(temp_val); + if(length > 64) { + printf("cifs.mount failed: password in credentials file too long\n"); + memset(line_buf,0, 4096); + if(mountpassword) { + memset(mountpassword,0,64); + } + exit(1); + } else { + if(mountpassword == NULL) { + mountpassword = calloc(65,1); + } + if(mountpassword) { + strncpy(mountpassword,temp_val,64); + got_password = 1; + } + } + } + } + } + fclose(fs); + if(line_buf) { + memset(line_buf,0,4096); + free(line_buf); + } + return 0; } -int parse_options(char * options) +static int get_password_from_file(int file_descript, char * filename) +{ + int rc = 0; + int i; + char c; + + if(mountpassword == NULL) + mountpassword = calloc(65,1); + else + memset(mountpassword, 0, 64); + + if(filename != NULL) { + file_descript = open(filename, O_RDONLY); + if(file_descript < 0) { + printf("cifs.mount failed. %s attempting to open password file %s\n", + strerror(errno),filename); + exit(1); + } + } + /* else file already open and fd provided */ + + for(i=0;i<64;i++) { + rc = read(file_descript,&c,1); + if(rc < 0) { + printf("cifs.mount failed. Error %s reading password file\n",strerror(errno)); + memset(mountpassword,0,64); + if(filename != NULL) + close(file_descript); + exit(1); + } else if(rc == 0) { + if(mountpassword[0] == 0) { + if(verboseflag) + printf("\nWarning: null password used since cifs password file empty"); + } + break; + } else /* read valid character */ { + if((c == 0) || (c == '\n')) { + break; + } else + mountpassword[i] = c; + } + } + if((i == 64) && (verboseflag)) { + printf("\nWarning: password longer than 64 characters specified in cifs password file"); + } + got_password = 1; + if(filename != NULL) { + close(file_descript); + } + + return rc; +} + +static int parse_options(char * options) { char * data; + char * percent_char = 0; char * value = 0; + char * next_keyword = 0; + int rc = 0; if (!options) return 1; + else + data = options; + + if(verboseflag) + printf("\n parsing options: %s", options); - while ((data = strsep(&options, ",")) != NULL) { - if (!*data) - continue; +/* while ((data = strsep(&options, ",")) != NULL) { */ + while(data != NULL) { + /* check if ends with trailing comma */ + if(*data == 0) + break; + + /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */ + /* data = next keyword */ + /* value = next value ie stuff after equal sign */ + + next_keyword = strchr(data,','); + + /* temporarily null terminate end of keyword=value pair */ + if(next_keyword) + *next_keyword = 0; + + /* if (!*data) + continue; */ + + /* temporarily null terminate keyword to make keyword and value distinct */ if ((value = strchr(data, '=')) != NULL) { - *value++ = '\0'; + *value = '\0'; + value++; } + if (strncmp(data, "user", 4) == 0) { if (!value || !*value) { printf("invalid or missing username\n"); @@ -87,113 +275,142 @@ int parse_options(char * options) } if (strnlen(value, 260) < 260) { got_user=1; - /* BB add check for format user%pass */ - /* if(strchr(username%passw) got_password = 1) */ + percent_char = strchr(value,'%'); + if(percent_char) { + *percent_char = ','; + if(mountpassword == NULL) + mountpassword = calloc(65,1); + if(mountpassword) { + if(got_password) + printf("\ncifs.mount warning - password specified twice\n"); + got_password = 1; + percent_char++; + strncpy(mountpassword, percent_char,64); + /* remove password from username */ + while(*percent_char != 0) { + *percent_char = ','; + percent_char++; + } + } + } } else { printf("username too long\n"); return 1; } - } else if (strncmp(data, "pass", 4) == 0) { - if (!value || !*value) { - if(got_password) { - printf("password specified twice, ignoring second\n"); - } else + } else if (strncmp(data, "pass", 4) == 0) { + if (!value || !*value) { + if(got_password) { + printf("\npassword specified twice, ignoring second\n"); + } else + got_password = 1; + } else if (strnlen(value, 17) < 17) { + if(got_password) + printf("\ncifs.mount warning - password specified twice\n"); got_password = 1; - } else if (strnlen(value, 17) < 17) { - got_password = 1; - } else { - printf("password too long\n"); - return 1; - } - } else if (strncmp(data, "ip", 2) == 0) { - if (!value || !*value) { - printf("target ip address argument missing"); - } else if (strnlen(value, 35) < 35) { - got_ip = 1; - } else { - printf("ip address too long\n"); - return 1; - } - } else if ((strncmp(data, "unc", 3) == 0) + } else { + printf("password too long\n"); + return 1; + } + } else if (strncmp(data, "ip", 2) == 0) { + if (!value || !*value) { + printf("target ip address argument missing"); + } else if (strnlen(value, 35) < 35) { + got_ip = 1; + } else { + printf("ip address too long\n"); + return 1; + } + } else if ((strncmp(data, "unc", 3) == 0) || (strncmp(data, "target", 6) == 0) || (strncmp(data, "path", 4) == 0)) { - if (!value || !*value) { - printf("invalid path to network resource\n"); - return 1; /* needs_arg; */ - } else if(strnlen(value,5) < 5) { - printf("UNC name too short"); - } + if (!value || !*value) { + printf("invalid path to network resource\n"); + return 1; /* needs_arg; */ + } else if(strnlen(value,5) < 5) { + printf("UNC name too short"); + } - if (strnlen(value, 300) < 300) { - got_unc = 1; - if (strncmp(value, "//", 2) == 0) { - if(got_unc) - printf("unc name specified twice, ignoring second\n"); - else - got_unc = 1; - } else if (strncmp(value, "\\\\", 2) != 0) { - printf("UNC Path does not begin with // or \\\\ \n"); + if (strnlen(value, 300) < 300) { + got_unc = 1; + if (strncmp(value, "//", 2) == 0) { + if(got_unc) + printf("unc name specified twice, ignoring second\n"); + else + got_unc = 1; + } else if (strncmp(value, "\\\\", 2) != 0) { + printf("UNC Path does not begin with // or \\\\ \n"); + return 1; + } else { + if(got_unc) + printf("unc name specified twice, ignoring second\n"); + else + got_unc = 1; + } + } else { + printf("CIFS: UNC name too long\n"); return 1; + } + } else if ((strncmp(data, "domain", 3) == 0) + || (strncmp(data, "workgroup", 5) == 0)) { + if (!value || !*value) { + printf("CIFS: invalid domain name\n"); + return 1; /* needs_arg; */ + } + if (strnlen(value, 65) < 65) { + got_domain = 1; } else { - if(got_unc) - printf("unc name specified twice, ignoring second\n"); - else - got_unc = 1; + printf("domain name too long\n"); + return 1; + } + } else if (strncmp(data, "cred", 4) == 0) { + if (value && *value) { + rc = open_cred_file(value); + if(rc) { + printf("error %d opening credential file %s",rc, value); + return 1; + } + } else { + printf("invalid credential file name specified\n"); + return 1; + } + } else if (strncmp(data, "uid", 3) == 0) { + if (value && *value) { + got_uid = 1; + } + } else if (strncmp(data, "gid", 3) == 0) { + if (value && *value) { + got_gid = 1; } - } else { - printf("CIFS: UNC name too long\n"); - return 1; - } - } else if ((strncmp(data, "domain", 3) == 0) - || (strncmp(data, "workgroup", 5) == 0)) { - if (!value || !*value) { - printf("CIFS: invalid domain name\n"); - return 1; /* needs_arg; */ - } - if (strnlen(value, 65) < 65) { - got_domain = 1; - } else { - printf("domain name too long\n"); - return 1; - } - } else if (strncmp(data, "uid", 3) == 0) { - if (value && *value) { - got_uid = 1; - } - } else if (strncmp(data, "gid", 3) == 0) { - if (value && *value) { - got_gid = 1; - } /* fmask and dmask synonyms for people used to smbfs syntax */ - } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) { - if (!value || !*value) { - printf ("Option '%s' requires a numerical argument\n", data); - return 1; - } + } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) { + if (!value || !*value) { + printf ("Option '%s' requires a numerical argument\n", data); + return 1; + } - if (value[0] != '0') { - printf ("WARNING: '%s' not expressed in octal.\n", data); - } + if (value[0] != '0') { + printf ("WARNING: '%s' not expressed in octal.\n", data); + } + + if (strcmp (data, "fmask") == 0) { + printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n"); + data = "file_mode"; + } + } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) { + if (!value || !*value) { + printf ("Option '%s' requires a numerical argument\n", data); + return 1; + } + + if (value[0] != '0') { + printf ("WARNING: '%s' not expressed in octal.\n", data); + } - if (strcmp (data, "fmask") == 0) { - printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n"); - data = "file_mode"; - } - } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) { - if (!value || !*value) { - printf ("Option '%s' requires a numerical argument\n", data); - return 1; - } - - if (value[0] != '0') { - printf ("WARNING: '%s' not expressed in octal.\n", data); - } - - if (strcmp (data, "dmask") == 0) { - printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n"); - data = "dir_mode"; - } - } /* else if (strnicmp(data, "port", 4) == 0) { + if (strcmp (data, "dmask") == 0) { + printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n"); + data = "dir_mode"; + } + } /* else if (strnicmp(data, "port", 4) == 0) { if (value && *value) { vol->port = simple_strtoul(value, &value, 0); @@ -214,6 +431,22 @@ int parse_options(char * options) } else printf("CIFS: Unknown mount option %s\n",data); */ + + /* move to next option */ + data = next_keyword+1; + + /* put overwritten equals sign back */ + if(value) { + value--; + *value = '='; + } + + /* put previous overwritten comma back */ + if(next_keyword) + *next_keyword = ','; + else + data = 0; + } return 0; } @@ -226,8 +459,7 @@ char * parse_server(char * unc_name) char * ipaddress_string = NULL; struct hostent * host_entry; struct in_addr server_ipaddr; - int rc,j; - char temp[64]; + int rc; if(length > 1023) { printf("mount error: UNC name too long"); @@ -244,7 +476,6 @@ char * parse_server(char * unc_name) printf("\nMounting the DFS root for domain not implemented yet"); return 0; } else { - /* BB add support for \\\\ not just // */ if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) { printf("mount error: improperly formatted UNC name."); printf(" %s does not begin with \\\\ or //\n",unc_name); @@ -300,21 +531,19 @@ static struct option longopts[] = { { "rw", 0, 0, 'w' }, { "options", 1, 0, 'o' }, { "types", 1, 0, 't' }, - { "replace", 0, 0, 129 }, - { "after", 0, 0, 130 }, - { "before", 0, 0, 131 }, - { "over", 0, 0, 132 }, - { "move", 0, 0, 133 }, - { "rsize",1, 0, 136 }, - { "wsize",1, 0, 137 }, - { "uid", 1, 0, 138}, - { "gid", 1, 0, 139}, + { "rsize",1, 0, 'R' }, + { "wsize",1, 0, 'W' }, + { "uid", 1, 0, '1'}, + { "gid", 1, 0, '2'}, { "uuid",1,0,'U' }, - { "user",1,0,140}, - { "username",1,0,140}, - { "dom",1,0,141}, - { "domain",1,0,141}, - { "password",1,0,142}, + { "user",1,0,'u'}, + { "username",1,0,'u'}, + { "dom",1,0,'d'}, + { "domain",1,0,'d'}, + { "password",1,0,'p'}, + { "pass",1,0,'p'}, + { "credentials",1,0,'c'}, + { "port",1,0,'P'}, { NULL, 0, 0, 0 } }; @@ -330,13 +559,14 @@ int main(int argc, char ** argv) char * mountpoint; char * options; char * temp; - int rc,i; + int rc; int rsize = 0; int wsize = 0; int nomtab = 0; int uid = 0; int gid = 0; int optlen = 0; + int orgoptlen = 0; struct stat statbuf; struct utsname sysinfo; struct mntent mountent; @@ -354,56 +584,40 @@ int main(int argc, char ** argv) uname(&sysinfo); /* BB add workstation name and domain and pass down */ -/*#ifdef _GNU_SOURCE - printf(" node: %s machine: %s\n", sysinfo.nodename,sysinfo.machine); -#endif*/ - if(argc < 3) - mount_cifs_usage(); + +/* #ifdef _GNU_SOURCE + printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname); +#endif */ + share_name = argv[1]; mountpoint = argv[2]; + /* add sharename in opts string as unc= parm */ while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsU:vVwt:", longopts, NULL)) != -1) { switch (c) { -/* case 'a': - ++mount_all; - break; - case 'f': - ++fake; - break; - case 'F': - ++optfork; - break; */ - case 'h': /* help */ - mount_cifs_usage (); - break; -/* case 'i': - external_allowed = 0; - break; - case 'l': +/* No code to do the following options yet */ +/* case 'l': list_with_volumelabel = 1; break; case 'L': volumelabel = optarg; break; */ - case 'n': - ++nomtab; - break; - case 'o': - if (orgoptions) { - orgoptions = strcat(orgoptions, ","); - orgoptions = strcat(orgoptions,optarg); - } else - orgoptions = strdup(optarg); - break; +/* case 'a': + ++mount_all; + break; */ -/* case 'O': - if (test_opts) - test_opts = xstrconcat3(test_opts, ",", optarg); - else - test_opts = xstrdup(optarg); - break;*/ + case '?': + case 'h': /* help */ + mount_cifs_usage (); + exit(1); + case 'n': + ++nomtab; + break; + case 'o': + orgoptions = strdup(optarg); + break; case 'r': /* mount readonly */ flags |= MS_RDONLY; break; @@ -413,68 +627,78 @@ int main(int argc, char ** argv) case 'v': ++verboseflag; break; -/* case 'V': - printf ("mount: %s\n", version); - exit (0);*/ + case 'V': + printf ("mount.cifs version: %s.%s%s\n", + MOUNT_CIFS_VERSION_MAJOR, + MOUNT_CIFS_VERSION_MINOR, + MOUNT_CIFS_VENDOR_SUFFIX); + if(mountpassword) { + memset(mountpassword,0,64); + } + exit (0); case 'w': flags &= ~MS_RDONLY; break; -/* case 0: - break; - - case 128: - mounttype = MS_BIND; - break; - case 129: - mounttype = MS_REPLACE; - break; - case 130: - mounttype = MS_AFTER; - break; - case 131: - mounttype = MS_BEFORE; - break; - case 132: - mounttype = MS_OVER; - break; - case 133: - mounttype = MS_MOVE; - break; - case 135: - mounttype = (MS_BIND | MS_REC); - break; */ - case 136: + case 'R': rsize = atoi(optarg) ; break; - case 137: + case 'W': wsize = atoi(optarg); break; - case 138: + case '1': uid = atoi(optarg); break; - case 139: + case '2': gid = atoi(optarg); break; - case 140: + case 'u': got_user = 1; user_name = optarg; break; - case 141: + case 'd': domain_name = optarg; break; - case 142: - got_password = 1; - mountpassword = optarg; + case 'p': + if(mountpassword == NULL) + mountpassword = calloc(65,1); + if(mountpassword) { + got_password = 1; + strncpy(mountpassword,optarg,64); + } + break; + case 't': break; - case '?': default: - mount_cifs_usage (); + printf("unknown mount option %c\n",c); + mount_cifs_usage(); + exit(1); } } - /* canonicalize the path in argv[1]? */ + if(argc < 3) + mount_cifs_usage(); + + if (getenv("PASSWD")) { + if(mountpassword == NULL) + mountpassword = calloc(65,1); + if(mountpassword) { + strncpy(mountpassword,getenv("PASSWD"),64); + got_password = 1; + } + } else if (getenv("PASSWD_FD")) { + get_password_from_file(atoi(getenv("PASSWD_FD")),NULL); + } else if (getenv("PASSWD_FILE")) { + get_password_from_file(0, getenv("PASSWD_FILE")); + } + + ipaddr = parse_server(share_name); + + if (orgoptions && parse_options(orgoptions)) + return 1; + + /* BB save off path and pop after mount returns? */ + /* BB canonicalize the path in argv[1]? */ - /* BB save off path and pop after mount returns */ if(chdir(mountpoint)) { printf("mount error: can not change directory into mount target %s\n",mountpoint); } @@ -490,44 +714,26 @@ int main(int argc, char ** argv) } if((getuid() != 0) && (geteuid() == 0)) { - if((statbuf.st_uid == getuid()) && (S_IRWXU == statbuf.st_mode & S_IRWXU)) { + if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) { printf("setuid mount allowed\n"); } else { - printf("mount error: permission denied, not superuser and cifs.mount not installed SUID\n"); + printf("mount error: permission denied or not superuser and cifs.mount not installed SUID\n"); return -1; } } - ipaddr = parse_server(share_name); -/* if(share_name == NULL) - return 1; */ - if (orgoptions && parse_options(strdup(orgoptions))) - return 1; - if(got_user == 0) user_name = getusername(); -/* check username for user%password format */ - if(got_password == 0) { - if (getenv("PASSWD")) { - mountpassword = malloc(33); - if(mountpassword) { - strncpy(mountpassword,getenv("PASSWD"),32); - got_password = 1; - } -/* } else if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) { - get_password_file(); - got_password = 1;*/ /* BB add missing function */ - } else { - mountpassword = getpass("Password: "); /* BB obsolete */ - got_password = 1; - } + mountpassword = getpass("Password: "); /* BB obsolete */ + got_password = 1; } /* FIXME launch daemon (handles dfs name resolution and credential change) remember to clear parms and overwrite password field before launching */ if(orgoptions) { optlen = strlen(orgoptions); + orgoptlen = optlen; } else optlen = 0; if(share_name) @@ -560,19 +766,20 @@ int main(int argc, char ** argv) strcat(options,mountpassword); } strncat(options,",ver=",5); - strcat(options,MOUNT_CIFS_VERSION); + strcat(options,MOUNT_CIFS_VERSION_MAJOR); if(orgoptions) { strcat(options,","); strcat(options,orgoptions); } - /* printf("\noptions %s \n",options);*/ + if(verboseflag) + printf("\ncifs.mount kernel mount options %s \n",options); if(mount(share_name, mountpoint, "cifs", flags, options)) { /* remember to kill daemon on error */ switch (errno) { case 0: printf("mount failed but no error number set\n"); - return 0; + break; case ENODEV: printf("mount error: cifs filesystem not supported by the system\n"); break; @@ -580,6 +787,9 @@ int main(int argc, char ** argv) printf("mount error %d = %s\n",errno,strerror(errno)); } printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n"); + if(mountpassword) { + memset(mountpassword,0,64); + } return -1; } else { pmntfile = setmntent(MOUNTED, "a+"); @@ -596,6 +806,20 @@ int main(int argc, char ** argv) printf("could not update mount table\n"); } } + if(mountpassword) { + memset(mountpassword,0,64); + free(mountpassword); + } + + if(options) { + memset(options,0,optlen); + free(options); + } + + if(orgoptions) { + memset(orgoptions,0,orgoptlen); + free(orgoptions); + } return 0; } diff --git a/source3/configure.in b/source3/configure.in index 1121551efc..821ab3a1ea 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -187,7 +187,6 @@ AC_SUBST(CONFIG_LIBS) AC_ARG_ENABLE(debug, [ --enable-debug Turn on compiler debugging information (default=no)], [if eval "test x$enable_debug = xyes"; then - echo "DEBUGGING TURNED ON!!!!" CFLAGS="${CFLAGS} -g" fi]) @@ -1636,9 +1635,8 @@ for i in $LOOK_DIRS ; do save_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS -I$i/include" dnl This is here to handle -withval stuff for --with-libiconv - if test x"$ICONV_PATH_SPEC" = "xyes" ; then - LDFLAGS="-L$i/lib" - fi +dnl Perhaps we should always add a -L + LDFLAGS="$LDFLAGS -L$i/lib" LIBS= export LDFLAGS LIBS CPPFLAGS dnl Try to find iconv(3) @@ -1715,7 +1713,7 @@ dnl ]) LIBS="$ic_save_LIBS" if test x"$samba_cv_HAVE_NATIVE_ICONV" = x"yes"; then CPPFLAGS=$save_CPPFLAGS - CFLAGS_ADD_DIR(CPPFLAGS, "$i/include") + LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS if test x"$jm_cv_lib_iconv" != x; then LIBS="$LIBS -l$jm_cv_lib_iconv" @@ -2640,6 +2638,7 @@ if test x"$with_ads_support" != x"no"; then AC_CHECK_FUNC_EXT(krb5_get_permitted_enctypes, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_get_default_in_tkt_etypes, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_free_ktypes, $KRB5_LIBS) + AC_CHECK_FUNC_EXT(krb5_free_data_contents, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_principal_get_comp_string, $KRB5_LIBS) LIBS="$LIBS $KRB5_LIBS" @@ -3056,6 +3055,7 @@ samba_cv_TRY_QUOTAS=no samba_cv_RUN_QUOTA_TESTS=auto samba_cv_WITH_SYS_QUOTAS=auto samba_cv_TRY_SYS_QUOTAS=no +samba_cv_SYSQUOTA_FOUND=no; AC_MSG_CHECKING(whether to try disk-quotas support) AC_ARG_WITH(quotas, @@ -3125,6 +3125,11 @@ AC_MSG_CHECKING(whether to try the lib/sysquotas.c interface on ${host_os}) AC_MSG_RESULT(yes) samba_cv_TRY_SYS_QUOTAS=yes samba_cv_RUN_QUOTA_TESTS=yes + samba_cv_SYSQUOTA_FOUND=yes + AC_DEFINE(HAVE_QUOTACTL_LINUX,1,[Whether Linux quota support is available]) + samba_cv_sysquotas_file="lib/sysquotas_linux.c" + AC_DEFINE(HAVE_LINUX_XFS_QUOTAS,1,[Whether Linux xfs quota support is available]) + samba_cv_found_xfs_header=yes ;; *) AC_MSG_RESULT(no) @@ -3137,21 +3142,21 @@ fi # only check for quota stuff if --with-quotas if test x"$samba_cv_RUN_QUOTA_TESTS" != x"no"; then +# some broken header files need this +AC_CHECK_HEADER(asm/types.h,[ + AC_DEFINE(HAVE_ASM_TYPES_H,1,[check for ]) + AC_ADD_INCLUDE() + ]) + # For quotas on Veritas VxFS filesystems AC_CHECK_HEADERS(sys/fs/vx_quota.h) # For sys/quota.h and linux/quota.h AC_CHECK_HEADERS(sys/quota.h) -AC_CHECK_HEADERS(asm/types.h linux/quota.h) - -# For quotas on Linux XFS filesystems -AC_CHECK_HEADERS(linux/xqm.h linux/xfs_fs.h) -AC_CHECK_HEADERS(xfs/libxfs.h xfs/xqm.h xfs/xfs_fs.h) -# For linux > 2.5.56 -AC_CHECK_HEADERS(linux/dqblk_xfs.h) -# if we have struct if_dqblk in we should use it -AC_CACHE_CHECK([for struct if_dqblk in ],samba_cv_HAVE_STRUCT_IF_DQBLK, [ +if test x"$samba_cv_found_xfs_header" != x"yes"; then +# if we have xfs quota support (IRIX) we should use it +AC_CACHE_CHECK([for XFS QUOTA in ],samba_cv_HAVE_SYS_QUOTA_XFS, [ AC_TRY_COMPILE([ #include "confdefs.h" #ifdef HAVE_SYS_TYPES_H @@ -3160,28 +3165,12 @@ AC_TRY_COMPILE([ #ifdef HAVE_ASM_TYPES_H #include #endif -#include -],[struct if_dqblk D;], -samba_cv_HAVE_STRUCT_IF_DQBLK=yes,samba_cv_HAVE_STRUCT_IF_DQBLK=no)]) -if test "$samba_cv_HAVE_STRUCT_IF_DQBLK"x = "yes"x; then - AC_DEFINE(HAVE_STRUCT_IF_DQBLK,1,[struct if_dqblk]) +#include +],[int i = Q_XGETQUOTA;], +samba_cv_HAVE_SYS_QUOTA_XFS=yes,samba_cv_HAVE_SYS_QUOTA_XFS=no)]) +if test "$samba_cv_HAVE_SYS_QUOTA_XFS"x = "yes"x; then + samba_cv_found_xfs_header=yes fi - -# if we have struct mem_dqblk in we should use it -AC_CACHE_CHECK([for struct mem_dqblk in ],samba_cv_HAVE_STRUCT_MEM_DQBLK, [ -AC_TRY_COMPILE([ -#include "confdefs.h" -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_ASM_TYPES_H -#include -#endif -#include -],[struct mem_dqblk D;], -samba_cv_HAVE_STRUCT_MEM_DQBLK=yes,samba_cv_HAVE_STRUCT_MEM_DQBLK=no)]) -if test "$samba_cv_HAVE_STRUCT_MEM_DQBLK"x = "yes"x; then - AC_DEFINE(HAVE_STRUCT_MEM_DQBLK,1,[struct mem_dqblk]) fi # if we have struct dqblk .dqb_fsoftlimit instead of .dqb_isoftlimit on IRIX @@ -3201,7 +3190,6 @@ fi ################## # look for a working quota system -samba_cv_SYSQUOTA_FOUND=no; if test x"$samba_cv_SYSQUOTA_FOUND" != x"yes"; then AC_CACHE_CHECK([for long quotactl(int cmd, char *special, qid_t id, caddr_t addr)],samba_cv_HAVE_QUOTACTL_4A,[ @@ -3212,7 +3200,9 @@ AC_TRY_RUN_STRICT([ #include "${srcdir-.}/tests/sysquotas.c"],[$Werror_FLAGS],[$CPPFLAGS],[$LDFLAGS], samba_cv_HAVE_QUOTACTL_4A=yes,samba_cv_HAVE_QUOTACTL_4A=no,samba_cv_HAVE_QUOTACTL_4A=cross)]) if test x"$samba_cv_HAVE_QUOTACTL_4A" = x"yes"; then - samba_cv_SYSQUOTA_FOUND=yes;AC_DEFINE(HAVE_QUOTACTL_4A,1,[Whether long quotactl(int cmd, char *special, qid_t id, caddr_t addr) is available]) + samba_cv_SYSQUOTA_FOUND=yes; + AC_DEFINE(HAVE_QUOTACTL_4A,1,[Whether long quotactl(int cmd, char *special, qid_t id, caddr_t addr) is available]) + samba_cv_sysquotas_file="lib/sysquotas_4A.c" fi fi @@ -3226,7 +3216,9 @@ AC_TRY_RUN_STRICT([ samba_cv_HAVE_QUOTACTL_4B=yes,samba_cv_HAVE_QUOTACTL_4B=no,samba_cv_HAVE_QUOTACTL_4B=cross)]) if test x"$samba_cv_HAVE_QUOTACTL_4B" = x"yes"; then echo "int quotactl(const char *path, int cmd, int id, char *addr) is not reworked for the new sys_quota api" -# samba_cv_SYSQUOTA_FOUND=yes;AC_DEFINE(HAVE_QUOTACTL_4B,1,[Whether int quotactl(const char *path, int cmd, int id, char *addr) is available]) + samba_cv_SYSQUOTA_FOUND=yes; + AC_DEFINE(HAVE_QUOTACTL_4B,1,[Whether int quotactl(const char *path, int cmd, int id, char *addr) is available]) + samba_cv_sysquotas_file="lib/sysquotas_4B.c" fi fi @@ -3240,7 +3232,9 @@ AC_TRY_RUN_STRICT([ samba_cv_HAVE_QUOTACTL_3=yes,samba_cv_HAVE_QUOTACTL_3=no,samba_cv_HAVE_QUOTACTL_3=cross)]) if test x"$samba_cv_HAVE_QUOTACTL_3" = x"yes"; then echo "CRAY int quotactl (char *spec, int request, char *arg) is NOT reworked for the sys_quota api" -# samba_cv_SYSQUOTA_FOUND=yes;AC_DEFINE(HAVE_QUOTACTL_3,1,[Whether CRAY int quotactl (char *spec, int request, char *arg); is available]) + samba_cv_SYSQUOTA_FOUND=yes; + AC_DEFINE(HAVE_QUOTACTL_3,1,[Whether CRAY int quotactl (char *spec, int request, char *arg); is available]) + samba_cv_sysquotas_file="lib/sysquotas_3.c" fi fi @@ -3299,6 +3293,27 @@ AC_MSG_CHECKING(whether to use the new lib/sysquotas.c interface) fi fi +if test x"$samba_cv_SYSQUOTA_FOUND" != x"no" -a x"$samba_cv_found_xfs_header" = x"yes"; then +AC_CACHE_CHECK([whether the sys_quota interface works with XFS],samba_cv_SYSQUOTA_WORKS_XFS,[ +SAVE_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -I${srcdir-.}/ -I. -I${srcdir-.}/include -I${srcdir-.}/ubiqx -I${srcdir-.}/popt -I${srcdir-.}/smbwrapper -I${srcdir-.}/nsswitch" +AC_TRY_COMPILE([ +#include "confdefs.h" +#define NO_PROTO_H 1 +#define NO_CONFIG_H 1 +#define HAVE_SYS_QUOTAS 1 +#define HAVE_XFS_QUOTAS 1 +#include "${srcdir-.}/lib/sysquotas_xfs.c" +],[],samba_cv_SYSQUOTA_WORKS_XFS=yes,samba_cv_SYSQUOTA_WORKS_XFS=no) +CPPFLAGS="$SAVE_CPPFLAGS" +]) +if test x"$samba_cv_SYSQUOTA_WORKS_XFS" = x"yes"; then + if test x"$samba_cv_WE_USE_SYS_QUOTAS" = x"yes"; then + AC_DEFINE(HAVE_XFS_QUOTAS,1,[Whether xfs quota support is available]) + fi +fi +fi + AC_CACHE_CHECK([whether the old quota support works],samba_cv_QUOTA_WORKS,[ SAVE_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -I${srcdir-.}/ -I. -I${srcdir-.}/include -I${srcdir-.}/ubiqx -I${srcdir-.}/popt -I${srcdir-.}/smbwrapper -I${srcdir-.}/nsswitch" @@ -4021,9 +4036,15 @@ WINBIND_WINS_NSS="nsswitch/libnss_wins.$SHLIBEXT" WINBIND_NSS_LDSHFLAGS=$LDSHFLAGS case "$host_os" in - *linux*|*freebsd*) + *linux*) WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_linux.o" ;; + *freebsd5*) + # FreeBSD winbind client is implemented as a wrapper around + # the Linux version. + WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_freebsd.o \ + nsswitch/winbind_nss_linux.o" + ;; *irix*) # IRIX has differently named shared libraries WINBIND_NSS_EXTRA_OBJS="nsswitch/winbind_nss_irix.o" diff --git a/source3/include/printing.h b/source3/include/printing.h index 1d658a0768..bf7c61b251 100644 --- a/source3/include/printing.h +++ b/source3/include/printing.h @@ -21,8 +21,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" - /* This file defines the low-level printing system interfaces used by the SAMBA printing subsystem. diff --git a/source3/include/samba_linux_quota.h b/source3/include/samba_linux_quota.h new file mode 100644 index 0000000000..02b3e5169b --- /dev/null +++ b/source3/include/samba_linux_quota.h @@ -0,0 +1,336 @@ +#ifndef _SAMBA_LINUX_QUOTA_H_ +#define _SAMBA_LINUX_QUOTA_H_ +/* + Unix SMB/CIFS implementation. + Copyright (C) Andrew Tridgell 1994-2002 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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. +*/ + +/* + This file is needed because Quota support on Linux has + been broken since Linus kernel 2.4.x. It will only get + better (and this file be removed) when all the distributions + ship a glibc with a working quota.h file. This is very + bad. JRA. + + Original file came from Christoph Hellwig . + Massaged into one nasty include file (to stop us having to + add multiple files into Samba just for Linux braindamage) + by JRA. +*/ + +#undef QUOTABLOCK_SIZE + +#ifndef _QUOTAIO_LINUX_V1 +#define _QUOTAIO_LINUX_V1 + +/* + * Headerfile for old quotafile format + */ + +#include + +#define V1_DQBLK_SIZE_BITS 10 +#define V1_DQBLK_SIZE (1 << V1_DQBLK_SIZE_BITS) /* Size of one quota block in bytes in old format */ + +#define V1_DQOFF(__id) ((loff_t) ((__id) * sizeof(struct v1_disk_dqblk))) + +/* Structure of quota on disk */ +struct v1_disk_dqblk { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred limit on inodes */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +} __attribute__ ((packed)); + +/* Structure used for communication with kernel */ +struct v1_kern_dqblk { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +}; + +struct v1_dqstats { + u_int32_t lookups; + u_int32_t drops; + u_int32_t reads; + u_int32_t writes; + u_int32_t cache_hits; + u_int32_t allocated_dquots; + u_int32_t free_dquots; + u_int32_t syncs; +}; + +#ifndef Q_V1_GETQUOTA +#define Q_V1_GETQUOTA 0x300 +#endif +#ifndef Q_V1_SETQUOTA +#define Q_V1_SETQUOTA 0x400 +#endif + +#endif /* _QUOTAIO_LINUX_V1 */ + +/* + * + * Header file for disk format of new quotafile format + * + */ + +#ifndef _QUOTAIO_LINUX_V2 +#define _QUOTAIO_LINUX_V2 + +#include + +#ifndef _QUOTA_LINUX +#define _QUOTA_LINUX + +#include + +typedef u_int32_t qid_t; /* Type in which we store ids in memory */ +typedef u_int64_t qsize_t; /* Type in which we store size limitations */ + +#define MAXQUOTAS 2 +#define USRQUOTA 0 /* element used for user quotas */ +#define GRPQUOTA 1 /* element used for group quotas */ + +/* + * Definitions for the default names of the quotas files. + */ +#define INITQFNAMES { \ + "user", /* USRQUOTA */ \ + "group", /* GRPQUOTA */ \ + "undefined", \ +} + +/* + * Definitions of magics and versions of current quota files + */ +#define INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} + +/* Size of blocks in which are counted size limits in generic utility parts */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) + +/* Conversion routines from and to quota blocks */ +#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10)) +#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) + +/* + * Command definitions for the 'quotactl' system call. + * The commands are broken into a main command defined below + * and a subcommand that is used to convey the type of + * quota that is being manipulated (see above). + */ +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) + +#define Q_6_5_QUOTAON 0x0100 /* enable quotas */ +#define Q_6_5_QUOTAOFF 0x0200 /* disable quotas */ +#define Q_6_5_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ + +#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */ +#define Q_QUOTAON 0x800002 /* turn quotas on */ +#define Q_QUOTAOFF 0x800003 /* turn quotas off */ +#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */ +#define Q_GETINFO 0x800005 /* get information about quota files */ +#define Q_SETINFO 0x800006 /* set information about quota files */ +#define Q_GETQUOTA 0x800007 /* get user quota structure */ +#define Q_SETQUOTA 0x800008 /* set user quota structure */ + +/* + * Quota structure used for communication with userspace via quotactl + * Following flags are used to specify which fields are valid + */ +#define QIF_BLIMITS 1 +#define QIF_SPACE 2 +#define QIF_ILIMITS 4 +#define QIF_INODES 8 +#define QIF_BTIME 16 +#define QIF_ITIME 32 +#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS) +#define QIF_USAGE (QIF_SPACE | QIF_INODES) +#define QIF_TIMES (QIF_BTIME | QIF_ITIME) +#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES) + +struct if_dqblk { + u_int64_t dqb_bhardlimit; + u_int64_t dqb_bsoftlimit; + u_int64_t dqb_curspace; + u_int64_t dqb_ihardlimit; + u_int64_t dqb_isoftlimit; + u_int64_t dqb_curinodes; + u_int64_t dqb_btime; + u_int64_t dqb_itime; + u_int32_t dqb_valid; +}; + +/* + * Structure used for setting quota information about file via quotactl + * Following flags are used to specify which fields are valid + */ +#define IIF_BGRACE 1 +#define IIF_IGRACE 2 +#define IIF_FLAGS 4 +#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) + +struct if_dqinfo { + u_int64_t dqi_bgrace; + u_int64_t dqi_igrace; + u_int32_t dqi_flags; + u_int32_t dqi_valid; +}; + +/* Quota format identifiers */ +#define QFMT_VFS_OLD 1 +#define QFMT_VFS_V0 2 + +/* Flags supported by kernel */ +#define V1_DQF_RSQUASH 1 + +/* Ioctl for getting quota size */ +#include +#ifndef FIOQSIZE + #if defined(__alpha__) || defined(__powerpc__) || defined(__sh__) || defined(__sparc__) || defined(__sparc64__) + #define FIOQSIZE _IOR('f', 128, loff_t) + #elif defined(__arm__) || defined(__mc68000__) || defined(__s390__) + #define FIOQSIZE 0x545E + #elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__ia64__) || defined(__parisc__) || defined(__cris__) || defined(__hppa__) + #define FIOQSIZE 0x5460 + #elif defined(__mips__) || defined(__mips64__) + #define FIOQSIZE 0x6667 + #endif +#endif + +long quotactl __P((int, const char *, qid_t, caddr_t)); + +#endif /* _QUOTA_LINUX */ + +#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ +#define V2_DQBLKSIZE_BITS 10 +#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */ +#define V2_DQTREEOFF 1 /* Offset of tree in file in blOcks */ +#define V2_DQTREEDEPTH 4 /* Depth of quota tree */ +#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */ +#define V2_GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) +#define V2_GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)(buf)) + sizeof(struct v2_disk_dqdbheader))) +#define INIT_V2_VERSIONS { 0, 0} + +struct v2_disk_dqheader { + u_int32_t dqh_magic; /* Magic number identifying file */ + u_int32_t dqh_version; /* File version */ +} __attribute__ ((packed)); + +/* Flags for version specific files */ +#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ + +/* Header with type and version specific information */ +struct v2_disk_dqinfo { + u_int32_t dqi_bgrace; /* Time before block soft limit becomes hard limit */ + u_int32_t dqi_igrace; /* Time before inode soft limit becomes hard limit */ + u_int32_t dqi_flags; /* Flags for quotafile (DQF_*) */ + u_int32_t dqi_blocks; /* Number of blocks in file */ + u_int32_t dqi_free_blk; /* Number of first free block in the list */ + u_int32_t dqi_free_entry; /* Number of block with at least one free entry */ +} __attribute__ ((packed)); + +/* + * Structure of header of block with quota structures. It is padded to 16 bytes so + * there will be space for exactly 18 quota-entries in a block + */ +struct v2_disk_dqdbheader { + u_int32_t dqdh_next_free; /* Number of next block with free entry */ + u_int32_t dqdh_prev_free; /* Number of previous block with free entry */ + u_int16_t dqdh_entries; /* Number of valid entries in block */ + u_int16_t dqdh_pad1; + u_int32_t dqdh_pad2; +} __attribute__ ((packed)); + +/* Structure of quota for one user on disk */ +struct v2_disk_dqblk { + u_int32_t dqb_id; /* id this quota applies to */ + u_int32_t dqb_ihardlimit; /* absolute limit on allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + u_int32_t dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ + u_int64_t dqb_curspace; /* current space occupied (in bytes) */ + u_int64_t dqb_btime; /* time limit for excessive disk use */ + u_int64_t dqb_itime; /* time limit for excessive inode use */ +} __attribute__ ((packed)); + +/* Structure of quota for communication with kernel */ +struct v2_kern_dqblk { + unsigned int dqb_ihardlimit; + unsigned int dqb_isoftlimit; + unsigned int dqb_curinodes; + unsigned int dqb_bhardlimit; + unsigned int dqb_bsoftlimit; + qsize_t dqb_curspace; + time_t dqb_btime; + time_t dqb_itime; +}; + +/* Structure of quotafile info for communication with kernel */ +struct v2_kern_dqinfo { + unsigned int dqi_bgrace; + unsigned int dqi_igrace; + unsigned int dqi_flags; + unsigned int dqi_blocks; + unsigned int dqi_free_blk; + unsigned int dqi_free_entry; +}; + +/* Structure with gathered statistics from kernel */ +struct v2_dqstats { + u_int32_t lookups; + u_int32_t drops; + u_int32_t reads; + u_int32_t writes; + u_int32_t cache_hits; + u_int32_t allocated_dquots; + u_int32_t free_dquots; + u_int32_t syncs; + u_int32_t version; +}; + +#ifndef Q_V2_GETQUOTA +#define Q_V2_GETQUOTA 0x0D00 +#endif +#ifndef Q_V2_SETQUOTA +#define Q_V2_SETQUOTA 0x0E00 +#endif + +#endif /* _QUOTAIO_LINUX_V2 */ + +#ifndef QUOTABLOCK_SIZE +#define QUOTABLOCK_SIZE 1024 +#endif + +#endif /* _SAMBA_LINUX_QUOTA_H_ */ diff --git a/source3/include/samba_xfs_quota.h b/source3/include/samba_xfs_quota.h new file mode 100644 index 0000000000..1db435064a --- /dev/null +++ b/source3/include/samba_xfs_quota.h @@ -0,0 +1,165 @@ +#ifndef _SAMBA_LINUX_XFS_H_ +#define _SAMBA_LINUX_XFS_H_ + +#ifndef _QUOTAIO_LINUX_XFS +#define _QUOTAIO_LINUX_XFS + +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#define XQM_CMD(cmd) ( ('X'<<8)+(cmd) ) +#define IS_XQM_CMD(cmd) ( ((int)(cmd)>>8) == 'X' ) + +/* + * Disk quota - quotactl(2) commands for XFS Quota Manager (XQM). + */ +#define Q_XQUOTAON XQM_CMD(0x1) /* enable quota accounting/enforcement */ +#define Q_XQUOTAOFF XQM_CMD(0x2) /* disable quota accounting/enforcement */ +#define Q_XGETQUOTA XQM_CMD(0x3) /* get disk limits & usage */ +#define Q_XSETQLIM XQM_CMD(0x4) /* set disk limits only */ +#define Q_XGETQSTAT XQM_CMD(0x5) /* returns fs_quota_stat_t struct */ +#define Q_XQUOTARM XQM_CMD(0x6) /* free quota files' space */ + +/* + * fs_disk_quota structure: + * + * This contains the current quota information regarding a user/proj/group. + * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of + * 512 bytes. + */ +#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ +typedef struct fs_disk_quota { + u_int8_t d_version; /* version of this structure */ + u_int8_t d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ + u_int16_t d_fieldmask; /* field specifier */ + u_int32_t d_id; /* user, project, or group ID */ + u_int64_t d_blk_hardlimit; /* absolute limit on disk blks */ + u_int64_t d_blk_softlimit; /* preferred limit on disk blks */ + u_int64_t d_ino_hardlimit; /* maximum # allocated inodes */ + u_int64_t d_ino_softlimit; /* preferred inode limit */ + u_int64_t d_bcount; /* # disk blocks owned by the user */ + u_int64_t d_icount; /* # inodes owned by the user */ + int32_t d_itimer; /* zero if within inode limits */ + /* if not, we refuse service */ + int32_t d_btimer; /* similar to above; for disk blocks */ + u_int16_t d_iwarns; /* # warnings issued wrt num inodes */ + u_int16_t d_bwarns; /* # warnings issued wrt disk blocks */ + int32_t d_padding2; /* padding2 - for future use */ + u_int64_t d_rtb_hardlimit; /* absolute limit on realtime blks */ + u_int64_t d_rtb_softlimit; /* preferred limit on RT disk blks */ + u_int64_t d_rtbcount; /* # realtime blocks owned */ + int32_t d_rtbtimer; /* similar to above; for RT disk blks */ + u_int16_t d_rtbwarns; /* # warnings issued wrt RT disk blks */ + int16_t d_padding3; /* padding3 - for future use */ + char d_padding4[8]; /* yet more padding */ +} fs_disk_quota_t; + +/* + * These fields are sent to Q_XSETQLIM to specify fields that need to change. + */ +#define FS_DQ_ISOFT (1<<0) +#define FS_DQ_IHARD (1<<1) +#define FS_DQ_BSOFT (1<<2) +#define FS_DQ_BHARD (1<<3) +#define FS_DQ_RTBSOFT (1<<4) +#define FS_DQ_RTBHARD (1<<5) +#define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ + FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) +/* + * These timers can only be set in super user's dquot. For others, timers are + * automatically started and stopped. Superusers timer values set the limits + * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values + * defined below are used. + * These values also apply only to the d_fieldmask field for Q_XSETQLIM. + */ +#define FS_DQ_BTIMER (1<<6) +#define FS_DQ_ITIMER (1<<7) +#define FS_DQ_RTBTIMER (1<<8) +#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) + +/* + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). These may be modified by the quotactl(2) + * system call with the Q_XSETQLIM command. + */ +#define DQ_FTIMELIMIT (7 * 24*60*60) /* 1 week */ +#define DQ_BTIMELIMIT (7 * 24*60*60) /* 1 week */ + +/* + * Various flags related to quotactl(2). Only relevant to XFS filesystems. + */ +#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ +#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ +#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ +#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ + +#define XFS_USER_QUOTA (1<<0) /* user quota type */ +#define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */ +#define XFS_GROUP_QUOTA (1<<2) /* group quota type */ + +/* + * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. + * Provides a centralized way to get meta infomation about the quota subsystem. + * eg. space taken up for user and group quotas, number of dquots currently + * incore. + */ +#define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ + +/* + * Some basic infomation about 'quota files'. + */ +typedef struct fs_qfilestat { + u_int64_t qfs_ino; /* inode number */ + u_int64_t qfs_nblks; /* number of BBs 512-byte-blks */ + u_int32_t qfs_nextents; /* number of extents */ +} fs_qfilestat_t; + +typedef struct fs_quota_stat { + u_int8_t qs_version; /* version number for future changes */ + u_int16_t qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ + u_int8_t qs_pad; /* unused */ + fs_qfilestat_t qs_uquota; /* user quota storage information */ + fs_qfilestat_t qs_gquota; /* group quota storage information */ + u_int32_t qs_incoredqs; /* number of dquots incore */ + int32_t qs_btimelimit; /* limit for blks timer */ + int32_t qs_itimelimit; /* limit for inodes timer */ + int32_t qs_rtbtimelimit; /* limit for rt blks timer */ + u_int16_t qs_bwarnlimit; /* limit for num warnings */ + u_int16_t qs_iwarnlimit; /* limit for num warnings */ +} fs_quota_stat_t; + +#endif /* _QUOTAIO_LINUX_XFS */ + +#endif /* _SAMBA_LINUX_XFS_H_ */ diff --git a/source3/include/sysquotas.h b/source3/include/sysquotas.h index b803e6277a..bfb9466b39 100644 --- a/source3/include/sysquotas.h +++ b/source3/include/sysquotas.h @@ -23,150 +23,6 @@ #ifdef HAVE_SYS_QUOTAS -/* Sometimes we need this on linux for linux/quota.h */ -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_ASM_TYPES_H -#include -#endif - -/* - * This shouldn't be neccessary - it should be /usr/include/sys/quota.h - * Unfortunately, RH7.1 ships with a different quota system using struct mem_dqblk - * rather than the struct dqblk defined in /usr/include/sys/quota.h. - * This means we must include linux/quota.h to have a hope of working on - * RH7.1 systems. And it also means this breaks if the kernel is upgraded - * to a Linus 2.4.x (where x > the minor number shipped with RH7.1) until - * Linus synchronises with the AC patches. Sometimes I *hate* Linux :-). JRA. - */ -#ifdef HAVE_LINUX_QUOTA_H -#include -#elif defined(HAVE_SYS_QUOTA_H) -#include -#endif - -#if defined(HAVE_STRUCT_IF_DQBLK) -# define SYS_DQBLK if_dqblk -# define dqb_curblocks dqb_curspace/bsize -#elif defined(HAVE_STRUCT_MEM_DQBLK) -# define SYS_DQBLK mem_dqblk -# define dqb_curblocks dqb_curspace/bsize -#else /* STRUCT_DQBLK */ -# define SYS_DQBLK dqblk -#endif - -#ifndef Q_SETQLIM -#define Q_SETQLIM Q_SETQUOTA -#endif - -/********************************************* - check for XFS QUOTA MANAGER - *********************************************/ -/* on linux */ -#ifdef HAVE_LINUX_XQM_H -# include -# define HAVE_XFS_QUOTA -#else -# ifdef HAVE_XFS_XQM_H -# include -# define HAVE_XFS_QUOTA -# else -# ifdef HAVE_LINUX_DQBLK_XFS_H -# include -# define HAVE_XFS_QUOTA -# endif -# endif -#endif -/* on IRIX */ -#ifdef Q_XGETQUOTA -# ifndef HAVE_XFS_QUOTA -# define HAVE_XFS_QUOTA -# ifndef Q_XQUOTAON -# define Q_XQUOTAON Q_QUOTAON -# endif /* Q_XQUOTAON */ -# ifndef Q_XQUOTAOFF -# define Q_XQUOTAOFF Q_QUOTAOFF -# endif /* Q_XQUOTAOFF */ -# ifndef Q_XGETQSTAT -# define Q_XGETQSTAT Q_GETQSTAT -# endif /* Q_XGETQSTAT */ -# endif /* HAVE_XFS_QUOTA */ -#endif /* Q_XGETQUOTA */ - -#ifdef HAVE_XFS_QUOTA -/* Linux has BBSIZE in - * or - * IRIX has BBSIZE in - */ -#ifdef HAVE_LINUX_XFS_FS_H -#include -#elif defined(HAVE_XFS_XFS_FS_H) -#include -#endif /* *_XFS_FS_H */ - -#ifndef BBSHIFT -#define BBSHIFT 9 -#endif /* BBSHIFT */ -#ifndef BBSIZE -#define BBSIZE (1< #define HAVE_MNTENT 1 @@ -178,10 +34,6 @@ #endif /* HAVE_SYS_QUOTAS */ -#ifndef QUOTABLOCK_SIZE -#define QUOTABLOCK_SIZE 1024 -#endif - /************************************************** Some stuff for the sys_quota api. **************************************************/ @@ -217,4 +69,8 @@ typedef struct _SMB_DISK_QUOTA { uint32 qflags; } SMB_DISK_QUOTA; +#ifndef QUOTABLOCK_SIZE +#define QUOTABLOCK_SIZE 1024 +#endif + #endif /*_SYSQUOTAS_H */ diff --git a/source3/intl/lang_tdb.c b/source3/intl/lang_tdb.c index b98e5734cb..fe2ad5b2fc 100644 --- a/source3/intl/lang_tdb.c +++ b/source3/intl/lang_tdb.c @@ -176,7 +176,8 @@ BOOL lang_tdb_init(const char *lang) const char *lang_msg(const char *msgid) { TDB_DATA key, data; - char *p, *q, *msgid_quoted; + const char *p; + char *q, *msgid_quoted; int count; lang_tdb_init(NULL); diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c index 7903dfd3f6..1c6058a43e 100644 --- a/source3/lib/charcnv.c +++ b/source3/lib/charcnv.c @@ -192,7 +192,7 @@ static size_t convert_string_internal(charset_t from, charset_t to, i_len=srclen; o_len=destlen; - retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len); + retval = smb_iconv(descriptor, (char **)&inbuf, &i_len, &outbuf, &o_len); if(retval==(size_t)-1) { const char *reason="unknown error"; switch(errno) { @@ -426,7 +426,7 @@ convert: i_len = srclen; o_len = destlen; retval = smb_iconv(descriptor, - &inbuf, &i_len, + (char **)&inbuf, &i_len, &outbuf, &o_len); if(retval == (size_t)-1) { const char *reason="unknown error"; diff --git a/source3/lib/sysquotas.c b/source3/lib/sysquotas.c index 3223ecb580..6883444e00 100644 --- a/source3/lib/sysquotas.c +++ b/source3/lib/sysquotas.c @@ -24,255 +24,6 @@ #ifdef HAVE_SYS_QUOTAS #if defined(HAVE_QUOTACTL_4A) -/* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */ -/* this is used by: linux,HPUX,IRIX */ - -/**************************************************************************** - Abstract out the old and new Linux quota get calls. -****************************************************************************/ -static int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) -{ - int ret = -1; - uint32 qflags = 0; - struct SYS_DQBLK D; - SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; - - if (!path||!bdev||!dp) - smb_panic("sys_get_vfs_quota: called with NULL pointer"); - - ZERO_STRUCT(D); - ZERO_STRUCT(*dp); - dp->qtype = qtype; - - switch (qtype) { - case SMB_USER_QUOTA_TYPE: - if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (CADDR_T)&D))) { - return ret; - } - - if ((D.dqb_curblocks==0)&& - (D.dqb_bsoftlimit==0)&& - (D.dqb_bhardlimit==0)) { - /* the upper layer functions don't want empty quota records...*/ - return -1; - } - - break; -#ifdef HAVE_GROUP_QUOTA - case SMB_GROUP_QUOTA_TYPE: - if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (CADDR_T)&D))) { - return ret; - } - - if ((D.dqb_curblocks==0)&& - (D.dqb_bsoftlimit==0)&& - (D.dqb_bhardlimit==0)) { - /* the upper layer functions don't want empty quota records...*/ - return -1; - } - - break; -#endif /* HAVE_GROUP_QUOTA */ - case SMB_USER_FS_QUOTA_TYPE: - id.uid = getuid(); - - if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (CADDR_T)&D))==0) { - qflags |= QUOTAS_DENY_DISK; - } - - ret = 0; - break; -#ifdef HAVE_GROUP_QUOTA - case SMB_GROUP_FS_QUOTA_TYPE: - id.gid = getgid(); - - if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (CADDR_T)&D))==0) { - qflags |= QUOTAS_DENY_DISK; - } - - ret = 0; - break; -#endif /* HAVE_GROUP_QUOTA */ - default: - errno = ENOSYS; - return -1; - } - - dp->bsize = bsize; - dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; - dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; - dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; - dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; - dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; - dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks; - - - dp->qflags = qflags; - - return ret; -} - -/**************************************************************************** - Abstract out the old and new Linux quota set calls. -****************************************************************************/ - -static int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) -{ - int ret = -1; - uint32 qflags = 0; - uint32 oldqflags = 0; - struct SYS_DQBLK D; - SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; - - if (!path||!bdev||!dp) - smb_panic("sys_set_vfs_quota: called with NULL pointer"); - - ZERO_STRUCT(D); - - if (bsize == dp->bsize) { - D.dqb_bsoftlimit = dp->softlimit; - D.dqb_bhardlimit = dp->hardlimit; - D.dqb_ihardlimit = dp->ihardlimit; - D.dqb_isoftlimit = dp->isoftlimit; - } else { - D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize; - D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize; - D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize; - D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize; - } - - qflags = dp->qflags; - - switch (qtype) { - case SMB_USER_QUOTA_TYPE: - ret = quotactl(QCMD(Q_SETQLIM,USRQUOTA), bdev, id.uid, (CADDR_T)&D); - break; -#ifdef HAVE_GROUP_QUOTA - case SMB_GROUP_QUOTA_TYPE: - ret = quotactl(QCMD(Q_SETQLIM,GRPQUOTA), bdev, id.gid, (CADDR_T)&D); - break; -#endif /* HAVE_GROUP_QUOTA */ - case SMB_USER_FS_QUOTA_TYPE: - /* this stuff didn't work as it should: - * switching on/off quota via quotactl() - * didn't work! - * So we just return 0 - * --metze - * - * On HPUX we didn't have the mount path, - * we need to fix sys_path_to_bdev() - * - */ -#if 0 - id.uid = getuid(); - - ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (CADDR_T)&D); - - if ((qflags"AS_DENY_DISK)||(qflags"AS_ENABLED)) { - if (ret == 0) { - char *quota_file = NULL; - - asprintf("a_file,"/%s/%s%s",path, QUOTAFILENAME,USERQUOTAFILE_EXTENSION); - if (quota_file == NULL) { - DEBUG(0,("asprintf() failed!\n")); - errno = ENOMEM; - return -1; - } - - ret = quotactl(QCMD(Q_QUOTAON,USRQUOTA), bdev, -1,(CADDR_T)quota_file); - } else { - ret = 0; - } - } else { - if (ret != 0) { - /* turn off */ - ret = quotactl(QCMD(Q_QUOTAOFF,USRQUOTA), bdev, -1, (CADDR_T)0); - } else { - ret = 0; - } - } - - DEBUG(0,("vfs_fs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n", - ret,errno,strerror(errno),id.uid,bdev)); -#else - id.uid = getuid(); - - if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (CADDR_T)&D))==0) { - oldqflags |= QUOTAS_DENY_DISK; - } - - if (oldqflags == qflags) { - ret = 0; - } else { - ret = -1; - } -#endif - break; -#ifdef HAVE_GROUP_QUOTA - case SMB_GROUP_FS_QUOTA_TYPE: - /* this stuff didn't work as it should: - * switching on/off quota via quotactl() - * didn't work! - * So we just return 0 - * --metze - * - * On HPUX we didn't have the mount path, - * we need to fix sys_path_to_bdev() - * - */ -#if 0 - id.gid = getgid(); - - ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id, (CADDR_T)&D); - - if ((qflags"AS_DENY_DISK)||(qflags"AS_ENABLED)) { - if (ret == 0) { - char *quota_file = NULL; - - asprintf("a_file,"/%s/%s%s",path, QUOTAFILENAME,GROUPQUOTAFILE_EXTENSION); - if (quota_file == NULL) { - DEBUG(0,("asprintf() failed!\n")); - errno = ENOMEM; - return -1; - } - - ret = quotactl(QCMD(Q_QUOTAON,GRPQUOTA), bdev, -1,(CADDR_T)quota_file); - } else { - ret = 0; - } - } else { - if (ret != 0) { - /* turn off */ - ret = quotactl(QCMD(Q_QUOTAOFF,GRPQUOTA), bdev, -1, (CADDR_T)0); - } else { - ret = 0; - } - } - - DEBUG(0,("vfs_fs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n", - ret,errno,strerror(errno),id.gid,bdev)); -#else - id.gid = getgid(); - - if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (CADDR_T)&D))==0) { - oldqflags |= QUOTAS_DENY_DISK; - } - - if (oldqflags == qflags) { - ret = 0; - } else { - ret = -1; - } -#endif - break; -#endif /* HAVE_GROUP_QUOTA */ - default: - errno = ENOSYS; - return -1; - } - - return ret; -} /*#endif HAVE_QUOTACTL_4A */ #elif defined(HAVE_QUOTACTL_4B) @@ -287,30 +38,6 @@ static int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_ /* #endif HAVE_QUOTACTL_3 */ #else /* NO_QUOTACTL_USED */ -static int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) -{ - int ret = -1; - - if (!path||!bdev||!dp) - smb_panic("sys_get_vfs_quota: called with NULL pointer"); - - errno = ENOSYS; - - return ret; -} - -static int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) -{ - int ret = -1; - - if (!path||!bdev||!dp) - smb_panic("sys_set_vfs_quota: called with NULL pointer"); - - errno = ENOSYS; - - return ret; -} - #endif /* NO_QUOTACTL_USED */ #ifdef HAVE_MNTENT @@ -434,262 +161,6 @@ static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char } #endif - -/********************************************************* - if we have XFS QUOTAS we should use them - *********************************************************/ -#ifdef HAVE_XFS_QUOTA -/**************************************************************************** - Abstract out the XFS Quota Manager quota get call. -****************************************************************************/ -static int sys_get_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) -{ - int ret = -1; - uint32 qflags = 0; - SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE; - struct fs_disk_quota D; - struct fs_quota_stat F; - ZERO_STRUCT(D); - ZERO_STRUCT(F); - - if (!bdev||!dp) - smb_panic("sys_get_xfs_quota: called with NULL pointer"); - - ZERO_STRUCT(*dp); - dp->qtype = qtype; - - switch (qtype) { - case SMB_USER_QUOTA_TYPE: - if ((ret=quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), bdev, id.uid, (CADDR_T)&D))) - return ret; - break; -#ifdef HAVE_GROUP_QUOTA - case SMB_GROUP_QUOTA_TYPE: - if ((ret=quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), bdev, id.gid, (CADDR_T)&D))) - return ret; - break; -#endif /* HAVE_GROUP_QUOTA */ - case SMB_USER_FS_QUOTA_TYPE: - quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (CADDR_T)&F); - - if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) { - qflags |= QUOTAS_DENY_DISK; - } - else if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) { - qflags |= QUOTAS_ENABLED; - } - - ret = 0; - - break; -#ifdef HAVE_GROUP_QUOTA - case SMB_GROUP_FS_QUOTA_TYPE: - quotactl(QCMD(Q_XGETQSTAT,GRPQUOTA), bdev, -1, (CADDR_T)&F); - - if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) { - qflags |= QUOTAS_DENY_DISK; - } - else if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) { - qflags |= QUOTAS_ENABLED; - } - - ret = 0; - - break; -#endif /* HAVE_GROUP_QUOTA */ - default: - errno = ENOSYS; - return -1; - } - - dp->bsize = bsize; - dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit; - dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit; - dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit; - dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit; - dp->curinodes = (SMB_BIG_UINT)D.d_icount; - dp->curblocks = (SMB_BIG_UINT)D.d_bcount; - dp->qflags = qflags; - - return ret; -} - -/**************************************************************************** - Abstract out the XFS Quota Manager quota set call. -****************************************************************************/ -static int sys_set_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) -{ - int ret = -1; - uint32 qflags = 0; - SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE; - struct fs_disk_quota D; - struct fs_quota_stat F; - int q_on = 0; - int q_off = 0; - ZERO_STRUCT(D); - ZERO_STRUCT(F); - - if (!bdev||!dp) - smb_panic("sys_set_xfs_quota: called with NULL pointer"); - - if (bsize == dp->bsize) { - D.d_blk_softlimit = dp->softlimit; - D.d_blk_hardlimit = dp->hardlimit; - D.d_ino_hardlimit = dp->ihardlimit; - D.d_ino_softlimit = dp->isoftlimit; - } else { - D.d_blk_softlimit = (dp->softlimit*dp->bsize)/bsize; - D.d_blk_hardlimit = (dp->hardlimit*dp->bsize)/bsize; - D.d_ino_hardlimit = (dp->ihardlimit*dp->bsize)/bsize; - D.d_ino_softlimit = (dp->isoftlimit*dp->bsize)/bsize; - } - - qflags = dp->qflags; - - switch (qtype) { - case SMB_USER_QUOTA_TYPE: - D.d_fieldmask |= FS_DQ_LIMIT_MASK; - ret = quotactl(QCMD(Q_XSETQLIM,USRQUOTA), bdev, id.uid, (CADDR_T)&D); - break; -#ifdef HAVE_GROUP_QUOTA - case SMB_GROUP_QUOTA_TYPE: - D.d_fieldmask |= FS_DQ_LIMIT_MASK; - ret = quotactl(QCMD(Q_XSETQLIM,GRPQUOTA), bdev, id.gid, (CADDR_T)&D); - break; -#endif /* HAVE_GROUP_QUOTA */ - case SMB_USER_FS_QUOTA_TYPE: - quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (CADDR_T)&F); - - if (qflags & QUOTAS_DENY_DISK) { - if (!(F.qs_flags & XFS_QUOTA_UDQ_ENFD)) - q_on |= XFS_QUOTA_UDQ_ENFD; - if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT)) - q_on |= XFS_QUOTA_UDQ_ACCT; - - if (q_on != 0) { - ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (CADDR_T)&q_on); - } else { - ret = 0; - } - - } else if (qflags & QUOTAS_ENABLED) { - if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) - q_off |= XFS_QUOTA_UDQ_ENFD; - - if (q_off != 0) { - ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (CADDR_T)&q_off); - } else { - ret = 0; - } - - if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT)) - q_on |= XFS_QUOTA_UDQ_ACCT; - - if (q_on != 0) { - ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (CADDR_T)&q_on); - } else { - ret = 0; - } - } else { -#if 0 - /* Switch on XFS_QUOTA_UDQ_ACCT didn't work! - * only swittching off XFS_QUOTA_UDQ_ACCT work - */ - if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) - q_off |= XFS_QUOTA_UDQ_ENFD; - if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) - q_off |= XFS_QUOTA_UDQ_ACCT; - - if (q_off !=0) { - ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (CADDR_T)&q_off); - } else { - ret = 0; - } -#else - ret = -1; -#endif - } - - break; -#ifdef HAVE_GROUP_QUOTA - case SMB_GROUP_FS_QUOTA_TYPE: - quotactl(QCMD(Q_XGETQSTAT,GRPQUOTA), bdev, -1, (CADDR_T)&F); - - if (qflags & QUOTAS_DENY_DISK) { - if (!(F.qs_flags & XFS_QUOTA_UDQ_ENFD)) - q_on |= XFS_QUOTA_UDQ_ENFD; - if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT)) - q_on |= XFS_QUOTA_UDQ_ACCT; - - if (q_on != 0) { - ret = quotactl(QCMD(Q_XQUOTAON,GRPQUOTA),bdev, -1, (CADDR_T)&q_on); - } else { - ret = 0; - } - - } else if (qflags & QUOTAS_ENABLED) { - if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) - q_off |= XFS_QUOTA_UDQ_ENFD; - - if (q_off != 0) { - ret = quotactl(QCMD(Q_XQUOTAOFF,GRPQUOTA),bdev, -1, (CADDR_T)&q_off); - } else { - ret = 0; - } - - if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT)) - q_on |= XFS_QUOTA_UDQ_ACCT; - - if (q_on != 0) { - ret = quotactl(QCMD(Q_XQUOTAON,GRPQUOTA),bdev, -1, (CADDR_T)&q_on); - } else { - ret = 0; - } - } else { -#if 0 - /* Switch on XFS_QUOTA_UDQ_ACCT didn't work! - * only swittching off XFS_QUOTA_UDQ_ACCT work - */ - if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) - q_off |= XFS_QUOTA_UDQ_ENFD; - if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) - q_off |= XFS_QUOTA_UDQ_ACCT; - - if (q_off !=0) { - ret = quotactl(QCMD(Q_XQUOTAOFF,GRPQUOTA),bdev, -1, (CADDR_T)&q_off); - } else { - ret = 0; - } -#else - ret = -1; -#endif - } - - break; -#endif /* HAVE_GROUP_QUOTA */ - default: - errno = ENOSYS; - return -1; - } - - return ret; -} -#endif /* HAVE_XFS_QUOTA */ - - - - - - - - - - - - - - - /********************************************************************* Now the list of all filesystem specific quota systems we have found **********************************************************************/ diff --git a/source3/lib/sysquotas_4A.c b/source3/lib/sysquotas_4A.c new file mode 100644 index 0000000000..66b367f099 --- /dev/null +++ b/source3/lib/sysquotas_4A.c @@ -0,0 +1,318 @@ +/* + Unix SMB/CIFS implementation. + System QUOTA function wrappers for QUOTACTL_4A + Copyright (C) Stefan (metze) Metzmacher 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include "includes.h" + +#ifdef HAVE_QUOTACTL_4A +/* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */ +/* this is used by: HPUX,IRIX */ + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_ASM_TYPES_H +#include +#endif + +#ifdef HAVE_SYS_QUOTA_H +#include +#endif + +#ifndef Q_SETQLIM +#define Q_SETQLIM Q_SETQUOTA +#endif + +#ifndef QCMD +#define QCMD(x,y) x +#endif + +#ifndef QCMD +#define QCMD(x,y) x +#endif + +#ifdef GRPQUOTA +#define HAVE_GROUP_QUOTA +#endif + +#ifndef QUOTABLOCK_SIZE +#define QUOTABLOCK_SIZE DEV_BSIZE +#endif + +#ifdef HAVE_DQB_FSOFTLIMIT +#define dqb_isoftlimit dqb_fsoftlimit +#define dqb_ihardlimit dqb_fhardlimit +#define dqb_curinodes dqb_curfiles +#endif + +#ifdef INITQFNAMES +#define USERQUOTAFILE_EXTENSION ".user" +#else +#define USERQUOTAFILE_EXTENSION "" +#endif + +#if !defined(QUOTAFILENAME) && defined(QFILENAME) +#define QUOTAFILENAME QFILENAME +#endif + +/**************************************************************************** + Abstract out the quotactl_4A get calls. +****************************************************************************/ +int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + struct dqblk D; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + + ZERO_STRUCT(D); + ZERO_STRUCT(*dp); + dp->qtype = qtype; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (void *)&D))&&errno != EDQUOT) { + return ret; + } + + if ((D.dqb_curblocks==0)&& + (D.dqb_bsoftlimit==0)&& + (D.dqb_bhardlimit==0)) { + /* the upper layer functions don't want empty quota records...*/ + return -1; + } + + break; +#ifdef HAVE_GROUP_QUOTA + case SMB_GROUP_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (void *)&D))&&errno != EDQUOT) { + return ret; + } + + if ((D.dqb_curblocks==0)&& + (D.dqb_bsoftlimit==0)&& + (D.dqb_bhardlimit==0)) { + /* the upper layer functions don't want empty quota records...*/ + return -1; + } + + break; +#endif /* HAVE_GROUP_QUOTA */ + case SMB_USER_FS_QUOTA_TYPE: + id.uid = getuid(); + + if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (void *)&D))==0) { + qflags |= QUOTAS_DENY_DISK; + } + + ret = 0; + break; +#ifdef HAVE_GROUP_QUOTA + case SMB_GROUP_FS_QUOTA_TYPE: + id.gid = getgid(); + + if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (void *)&D))==0) { + qflags |= QUOTAS_DENY_DISK; + } + + ret = 0; + break; +#endif /* HAVE_GROUP_QUOTA */ + default: + errno = ENOSYS; + return -1; + } + + dp->bsize = bsize; + dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; + dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; + dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; + dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; + dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; + dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks; + + + dp->qflags = qflags; + + return ret; +} + +/**************************************************************************** + Abstract out the quotactl_4A set calls. +****************************************************************************/ +int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + uint32 oldqflags = 0; + struct dqblk D; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + + ZERO_STRUCT(D); + + if (bsize == dp->bsize) { + D.dqb_bsoftlimit = dp->softlimit; + D.dqb_bhardlimit = dp->hardlimit; + D.dqb_ihardlimit = dp->ihardlimit; + D.dqb_isoftlimit = dp->isoftlimit; + } else { + D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize; + D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize; + D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize; + D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize; + } + + qflags = dp->qflags; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + ret = quotactl(QCMD(Q_SETQLIM,USRQUOTA), bdev, id.uid, (void *)&D); + break; +#ifdef HAVE_GROUP_QUOTA + case SMB_GROUP_QUOTA_TYPE: + ret = quotactl(QCMD(Q_SETQLIM,GRPQUOTA), bdev, id.gid, (void *)&D); + break; +#endif /* HAVE_GROUP_QUOTA */ + case SMB_USER_FS_QUOTA_TYPE: + /* this stuff didn't work as it should: + * switching on/off quota via quotactl() + * didn't work! + * So we just return 0 + * --metze + * + * On HPUX we didn't have the mount path, + * we need to fix sys_path_to_bdev() + * + */ +#if 0 + id.uid = getuid(); + + ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (void *)&D); + + if ((qflags"AS_DENY_DISK)||(qflags"AS_ENABLED)) { + if (ret == 0) { + char *quota_file = NULL; + + asprintf("a_file,"/%s/%s%s",path, QUOTAFILENAME,USERQUOTAFILE_EXTENSION); + if (quota_file == NULL) { + DEBUG(0,("asprintf() failed!\n")); + errno = ENOMEM; + return -1; + } + + ret = quotactl(QCMD(Q_QUOTAON,USRQUOTA), bdev, -1,(void *)quota_file); + } else { + ret = 0; + } + } else { + if (ret != 0) { + /* turn off */ + ret = quotactl(QCMD(Q_QUOTAOFF,USRQUOTA), bdev, -1, (void *)0); + } else { + ret = 0; + } + } + + DEBUG(0,("vfs_fs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n", + ret,errno,strerror(errno),id.uid,bdev)); +#else + id.uid = getuid(); + + if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (void *)&D))==0) { + oldqflags |= QUOTAS_DENY_DISK; + } + + if (oldqflags == qflags) { + ret = 0; + } else { + ret = -1; + } +#endif + break; +#ifdef HAVE_GROUP_QUOTA + case SMB_GROUP_FS_QUOTA_TYPE: + /* this stuff didn't work as it should: + * switching on/off quota via quotactl() + * didn't work! + * So we just return 0 + * --metze + * + * On HPUX we didn't have the mount path, + * we need to fix sys_path_to_bdev() + * + */ +#if 0 + id.gid = getgid(); + + ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id, (void *)&D); + + if ((qflags"AS_DENY_DISK)||(qflags"AS_ENABLED)) { + if (ret == 0) { + char *quota_file = NULL; + + asprintf("a_file,"/%s/%s%s",path, QUOTAFILENAME,GROUPQUOTAFILE_EXTENSION); + if (quota_file == NULL) { + DEBUG(0,("asprintf() failed!\n")); + errno = ENOMEM; + return -1; + } + + ret = quotactl(QCMD(Q_QUOTAON,GRPQUOTA), bdev, -1,(void *)quota_file); + } else { + ret = 0; + } + } else { + if (ret != 0) { + /* turn off */ + ret = quotactl(QCMD(Q_QUOTAOFF,GRPQUOTA), bdev, -1, (void *)0); + } else { + ret = 0; + } + } + + DEBUG(0,("vfs_fs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n", + ret,errno,strerror(errno),id.gid,bdev)); +#else + id.gid = getgid(); + + if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (void *)&D))==0) { + oldqflags |= QUOTAS_DENY_DISK; + } + + if (oldqflags == qflags) { + ret = 0; + } else { + ret = -1; + } +#endif + break; +#endif /* HAVE_GROUP_QUOTA */ + default: + errno = ENOSYS; + return -1; + } + + return ret; +} + +#else /* HAVE_QUOTACTL_4A */ + void dummy_sysquotas_4A(void){} +#endif /* HAVE_QUOTACTL_4A */ diff --git a/source3/lib/sysquotas_linux.c b/source3/lib/sysquotas_linux.c new file mode 100644 index 0000000000..be42fa23f4 --- /dev/null +++ b/source3/lib/sysquotas_linux.c @@ -0,0 +1,485 @@ +/* + Unix SMB/CIFS implementation. + System QUOTA function wrappers for LINUX + Copyright (C) Stefan (metze) Metzmacher 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include "includes.h" + +#ifdef HAVE_QUOTACTL_LINUX + +#include "samba_linux_quota.h" + +/**************************************************************************** + Abstract out the v1 Linux quota get calls. +****************************************************************************/ +static int sys_get_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + struct v1_kern_dqblk D; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + + ZERO_STRUCT(D); + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) { + return ret; + } + + break; + case SMB_GROUP_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) { + return ret; + } + + break; + case SMB_USER_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) { + qflags |= QUOTAS_DENY_DISK; + } + + break; + case SMB_GROUP_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) { + qflags |= QUOTAS_DENY_DISK; + } + + break; + default: + errno = ENOSYS; + return -1; + } + + dp->bsize = bsize; + dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; + dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; + dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; + dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; + dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; + dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks; + + + dp->qflags = qflags; + + return ret; +} + +/**************************************************************************** + Abstract out the v1 Linux quota set calls. +****************************************************************************/ +static int sys_set_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + uint32 oldqflags = 0; + struct v1_kern_dqblk D; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + + ZERO_STRUCT(D); + + if (bsize == dp->bsize) { + D.dqb_bsoftlimit = dp->softlimit; + D.dqb_bhardlimit = dp->hardlimit; + D.dqb_ihardlimit = dp->ihardlimit; + D.dqb_isoftlimit = dp->isoftlimit; + } else { + D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize; + D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize; + D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize; + D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize; + } + + qflags = dp->qflags; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + ret = quotactl(QCMD(Q_V1_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D); + break; + case SMB_GROUP_QUOTA_TYPE: + ret = quotactl(QCMD(Q_V1_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D); + break; + case SMB_USER_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) { + oldqflags |= QUOTAS_DENY_DISK; + } + + break; + case SMB_GROUP_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) { + oldqflags |= QUOTAS_DENY_DISK; + } + + break; + default: + errno = ENOSYS; + return -1; + } + + return ret; +} + +/**************************************************************************** + Abstract out the v2 Linux quota get calls. +****************************************************************************/ +static int sys_get_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + struct v2_kern_dqblk D; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + + ZERO_STRUCT(D); + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) { + return ret; + } + + break; + case SMB_GROUP_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) { + return ret; + } + + break; + case SMB_USER_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) { + qflags |= QUOTAS_DENY_DISK; + } + + break; + case SMB_GROUP_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) { + qflags |= QUOTAS_DENY_DISK; + } + + break; + default: + errno = ENOSYS; + return -1; + } + + dp->bsize = bsize; + dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; + dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; + dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; + dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; + dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; + dp->curblocks = (SMB_BIG_UINT)D.dqb_curspace/bsize; + + + dp->qflags = qflags; + + return ret; +} + +/**************************************************************************** + Abstract out the v2 Linux quota set calls. +****************************************************************************/ +static int sys_set_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + uint32 oldqflags = 0; + struct v2_kern_dqblk D; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + + ZERO_STRUCT(D); + + if (bsize == dp->bsize) { + D.dqb_bsoftlimit = dp->softlimit; + D.dqb_bhardlimit = dp->hardlimit; + D.dqb_ihardlimit = dp->ihardlimit; + D.dqb_isoftlimit = dp->isoftlimit; + } else { + D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize; + D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize; + D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize; + D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize; + } + + qflags = dp->qflags; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + ret = quotactl(QCMD(Q_V2_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D); + break; + case SMB_GROUP_QUOTA_TYPE: + ret = quotactl(QCMD(Q_V2_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D); + break; + case SMB_USER_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) { + oldqflags |= QUOTAS_DENY_DISK; + } + + break; + case SMB_GROUP_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) { + oldqflags |= QUOTAS_DENY_DISK; + } + + break; + default: + errno = ENOSYS; + return -1; + } + + return ret; +} + +/**************************************************************************** + Abstract out the generic Linux quota get calls. +****************************************************************************/ +static int sys_get_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + struct if_dqblk D; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + + ZERO_STRUCT(D); + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) { + return ret; + } + + break; + case SMB_GROUP_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) { + return ret; + } + + break; + case SMB_USER_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) { + qflags |= QUOTAS_DENY_DISK; + } + + break; + case SMB_GROUP_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) { + qflags |= QUOTAS_DENY_DISK; + } + + break; + default: + errno = ENOSYS; + return -1; + } + + dp->bsize = bsize; + dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; + dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; + dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; + dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; + dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; + dp->curblocks = (SMB_BIG_UINT)D.dqb_curspace/bsize; + + + dp->qflags = qflags; + + return ret; +} + +/**************************************************************************** + Abstract out the gen Linux quota set calls. +****************************************************************************/ +static int sys_set_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + uint32 oldqflags = 0; + struct if_dqblk D; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + + ZERO_STRUCT(D); + + if (bsize == dp->bsize) { + D.dqb_bsoftlimit = dp->softlimit; + D.dqb_bhardlimit = dp->hardlimit; + D.dqb_ihardlimit = dp->ihardlimit; + D.dqb_isoftlimit = dp->isoftlimit; + } else { + D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize; + D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize; + D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize; + D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize; + } + + qflags = dp->qflags; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + ret = quotactl(QCMD(Q_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D); + break; + case SMB_GROUP_QUOTA_TYPE: + ret = quotactl(QCMD(Q_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D); + break; + case SMB_USER_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) { + oldqflags |= QUOTAS_DENY_DISK; + } + + break; + case SMB_GROUP_FS_QUOTA_TYPE: + if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) { + oldqflags |= QUOTAS_DENY_DISK; + } + + break; + default: + errno = ENOSYS; + return -1; + } + + return ret; +} + +/**************************************************************************** + Abstract out the Linux quota get calls. +****************************************************************************/ +int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + + if (!path||!bdev||!dp) + smb_panic("sys_set_vfs_quota: called with NULL pointer"); + + ZERO_STRUCT(*dp); + dp->qtype = qtype; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + case SMB_GROUP_QUOTA_TYPE: + if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) { + if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) { + if ((ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) { + return ret; + } + } + } + + if ((dp->curblocks==0)&& + (dp->softlimit==0)&& + (dp->hardlimit==0)) { + /* the upper layer functions don't want empty quota records...*/ + return -1; + } + + break; + case SMB_USER_FS_QUOTA_TYPE: + id.uid = getuid(); + + if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) { + if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) { + ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp); + } + } + + ret = 0; + break; + case SMB_GROUP_FS_QUOTA_TYPE: + id.gid = getgid(); + + if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) { + if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) { + ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp); + } + } + + ret = 0; + break; + default: + errno = ENOSYS; + return -1; + } + + return ret; +} + +/**************************************************************************** + Abstract out the Linux quota set calls. +****************************************************************************/ +int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 oldqflags = 0; + + if (!path||!bdev||!dp) + smb_panic("sys_set_vfs_quota: called with NULL pointer"); + + oldqflags = dp->qflags; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + case SMB_GROUP_QUOTA_TYPE: + if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) { + if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) { + if ((ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp))) { + return ret; + } + } + } + break; + case SMB_USER_FS_QUOTA_TYPE: + id.uid = getuid(); + + if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))) { + if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))) { + ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp); + } + } + + if (oldqflags == dp->qflags) { + ret = 0; + } else { + ret = -1; + } + break; + case SMB_GROUP_FS_QUOTA_TYPE: + id.gid = getgid(); + + if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))) { + if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))) { + ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp); + } + } + + if (oldqflags == dp->qflags) { + ret = 0; + } else { + ret = -1; + } + + break; + default: + errno = ENOSYS; + return -1; + } + + return ret; +} + +#else /* HAVE_QUOTACTL_LINUX */ + void dummy_sysquotas_linux(void){} +#endif /* HAVE_QUOTACTL_LINUX */ diff --git a/source3/lib/sysquotas_xfs.c b/source3/lib/sysquotas_xfs.c new file mode 100644 index 0000000000..6d7d9f9e6a --- /dev/null +++ b/source3/lib/sysquotas_xfs.c @@ -0,0 +1,306 @@ +/* + Unix SMB/CIFS implementation. + System QUOTA function wrappers for XFS + Copyright (C) Stefan (metze) Metzmacher 2003 + + 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" + +#ifndef HAVE_SYS_QUOTAS +#ifdef HAVE_XFS_QUOTAS +#undef HAVE_XFS_QUOTAS +#endif +#endif + +#ifdef HAVE_XFS_QUOTAS + +#ifdef HAVE_LINUX_XFS_QUOTAS +#include "samba_linux_quota.h" +#include "samba_xfs_quota.h" +#define HAVE_GROUP_QUOTA +#else /* IRIX */ +#include +#endif + +/* on IRIX */ +#ifndef Q_XQUOTAON +#define Q_XQUOTAON Q_QUOTAON +#endif /* Q_XQUOTAON */ +#ifndef Q_XQUOTAOFF +#define Q_XQUOTAOFF Q_QUOTAOFF +#endif /* Q_XQUOTAOFF */ +#ifndef Q_XGETQSTAT +#define Q_XGETQSTAT Q_GETQSTAT +#endif /* Q_XGETQSTAT */ + +/* currently doesn't support Group and Project quotas on IRIX + */ + +#ifndef QCMD +#define QCMD(x,y) x +#endif + +/* + * IRIX has BBSIZE in + */ +#ifndef BBSHIFT +#define BBSHIFT 9 +#endif /* BBSHIFT */ +#ifndef BBSIZE +#define BBSIZE (1<qtype = qtype; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + if ((ret=quotactl(QCMD(Q_XGETQUOTA,XFS_USER_QUOTA), bdev, id.uid, (caddr_t)&D))) + return ret; + break; +#ifdef HAVE_GROUP_QUOTA + case SMB_GROUP_QUOTA_TYPE: + if ((ret=quotactl(QCMD(Q_XGETQUOTA,XFS_GROUP_QUOTA), bdev, id.gid, (caddr_t)&D))) + return ret; + break; +#endif /* HAVE_GROUP_QUOTA */ + case SMB_USER_FS_QUOTA_TYPE: + quotactl(QCMD(Q_XGETQSTAT,XFS_USER_QUOTA), bdev, -1, (caddr_t)&F); + + if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) { + qflags |= QUOTAS_DENY_DISK; + } + else if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) { + qflags |= QUOTAS_ENABLED; + } + + ret = 0; + + break; +#ifdef HAVE_GROUP_QUOTA + case SMB_GROUP_FS_QUOTA_TYPE: + quotactl(QCMD(Q_XGETQSTAT,XFS_GROUP_QUOTA), bdev, -1, (caddr_t)&F); + + if (F.qs_flags & XFS_QUOTA_GDQ_ENFD) { + qflags |= QUOTAS_DENY_DISK; + } + else if (F.qs_flags & XFS_QUOTA_GDQ_ACCT) { + qflags |= QUOTAS_ENABLED; + } + + ret = 0; + + break; +#endif /* HAVE_GROUP_QUOTA */ + default: + errno = ENOSYS; + return -1; + } + + dp->bsize = bsize; + dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit; + dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit; + dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit; + dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit; + dp->curinodes = (SMB_BIG_UINT)D.d_icount; + dp->curblocks = (SMB_BIG_UINT)D.d_bcount; + dp->qflags = qflags; + + return ret; +} + +/**************************************************************************** + Abstract out the XFS Quota Manager quota set call. +****************************************************************************/ +int sys_set_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) +{ + int ret = -1; + uint32 qflags = 0; + SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE; + struct fs_disk_quota D; + struct fs_quota_stat F; + int q_on = 0; + int q_off = 0; + ZERO_STRUCT(D); + ZERO_STRUCT(F); + + if (!bdev||!dp) + smb_panic("sys_set_xfs_quota: called with NULL pointer"); + + if (bsize == dp->bsize) { + D.d_blk_softlimit = dp->softlimit; + D.d_blk_hardlimit = dp->hardlimit; + D.d_ino_hardlimit = dp->ihardlimit; + D.d_ino_softlimit = dp->isoftlimit; + } else { + D.d_blk_softlimit = (dp->softlimit*dp->bsize)/bsize; + D.d_blk_hardlimit = (dp->hardlimit*dp->bsize)/bsize; + D.d_ino_hardlimit = (dp->ihardlimit*dp->bsize)/bsize; + D.d_ino_softlimit = (dp->isoftlimit*dp->bsize)/bsize; + } + + qflags = dp->qflags; + + switch (qtype) { + case SMB_USER_QUOTA_TYPE: + D.d_fieldmask |= FS_DQ_LIMIT_MASK; + ret = quotactl(QCMD(Q_XSETQLIM,XFS_USER_QUOTA), bdev, id.uid, (caddr_t)&D); + break; +#ifdef HAVE_GROUP_QUOTA + case SMB_GROUP_QUOTA_TYPE: + D.d_fieldmask |= FS_DQ_LIMIT_MASK; + ret = quotactl(QCMD(Q_XSETQLIM,XFS_GROUP_QUOTA), bdev, id.gid, (caddr_t)&D); + break; +#endif /* HAVE_GROUP_QUOTA */ + case SMB_USER_FS_QUOTA_TYPE: + quotactl(QCMD(Q_XGETQSTAT,XFS_USER_QUOTA), bdev, -1, (caddr_t)&F); + + if (qflags & QUOTAS_DENY_DISK) { + if (!(F.qs_flags & XFS_QUOTA_UDQ_ENFD)) + q_on |= XFS_QUOTA_UDQ_ENFD; + if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT)) + q_on |= XFS_QUOTA_UDQ_ACCT; + + if (q_on != 0) { + ret = quotactl(QCMD(Q_XQUOTAON,XFS_USER_QUOTA),bdev, -1, (caddr_t)&q_on); + } else { + ret = 0; + } + + } else if (qflags & QUOTAS_ENABLED) { + if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) + q_off |= XFS_QUOTA_UDQ_ENFD; + + if (q_off != 0) { + ret = quotactl(QCMD(Q_XQUOTAOFF,XFS_USER_QUOTA),bdev, -1, (caddr_t)&q_off); + } else { + ret = 0; + } + + if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT)) + q_on |= XFS_QUOTA_UDQ_ACCT; + + if (q_on != 0) { + ret = quotactl(QCMD(Q_XQUOTAON,XFS_USER_QUOTA),bdev, -1, (caddr_t)&q_on); + } else { + ret = 0; + } + } else { +#if 0 + /* Switch on XFS_QUOTA_UDQ_ACCT didn't work! + * only swittching off XFS_QUOTA_UDQ_ACCT work + */ + if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) + q_off |= XFS_QUOTA_UDQ_ENFD; + if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) + q_off |= XFS_QUOTA_UDQ_ACCT; + + if (q_off !=0) { + ret = quotactl(QCMD(Q_XQUOTAOFF,XFS_USER_QUOTA),bdev, -1, (caddr_t)&q_off); + } else { + ret = 0; + } +#else + ret = -1; +#endif + } + + break; +#ifdef HAVE_GROUP_QUOTA + case SMB_GROUP_FS_QUOTA_TYPE: + quotactl(QCMD(Q_XGETQSTAT,XFS_GROUP_QUOTA), bdev, -1, (caddr_t)&F); + + if (qflags & QUOTAS_DENY_DISK) { + if (!(F.qs_flags & XFS_QUOTA_GDQ_ENFD)) + q_on |= XFS_QUOTA_GDQ_ENFD; + if (!(F.qs_flags & XFS_QUOTA_GDQ_ACCT)) + q_on |= XFS_QUOTA_GDQ_ACCT; + + if (q_on != 0) { + ret = quotactl(QCMD(Q_XQUOTAON,XFS_GROUP_QUOTA),bdev, -1, (caddr_t)&q_on); + } else { + ret = 0; + } + + } else if (qflags & QUOTAS_ENABLED) { + if (F.qs_flags & XFS_QUOTA_GDQ_ENFD) + q_off |= XFS_QUOTA_GDQ_ENFD; + + if (q_off != 0) { + ret = quotactl(QCMD(Q_XQUOTAOFF,XFS_GROUP_QUOTA),bdev, -1, (caddr_t)&q_off); + } else { + ret = 0; + } + + if (!(F.qs_flags & XFS_QUOTA_GDQ_ACCT)) + q_on |= XFS_QUOTA_GDQ_ACCT; + + if (q_on != 0) { + ret = quotactl(QCMD(Q_XQUOTAON,XFS_GROUP_QUOTA),bdev, -1, (caddr_t)&q_on); + } else { + ret = 0; + } + } else { +#if 0 + /* Switch on XFS_QUOTA_UDQ_ACCT didn't work! + * only swittching off XFS_QUOTA_UDQ_ACCT work + */ + if (F.qs_flags & XFS_QUOTA_GDQ_ENFD) + q_off |= XFS_QUOTA_GDQ_ENFD; + if (F.qs_flags & XFS_QUOTA_GDQ_ACCT) + q_off |= XFS_QUOTA_GDQ_ACCT; + + if (q_off !=0) { + ret = quotactl(QCMD(Q_XQUOTAOFF,XFS_GROUP_QUOTA),bdev, -1, (caddr_t)&q_off); + } else { + ret = 0; + } +#else + ret = -1; +#endif + } + + break; +#endif /* HAVE_GROUP_QUOTA */ + default: + errno = ENOSYS; + return -1; + } + + return ret; +} + +#else /* HAVE_XFS_QUOTAS */ + void dummy_sysquotas_xfs(void){} +#endif /* HAVE_XFS_QUOTAS */ diff --git a/source3/lib/talloctort.c b/source3/lib/talloctort.c index ad5de38581..0cdf693bb9 100644 --- a/source3/lib/talloctort.c +++ b/source3/lib/talloctort.c @@ -51,9 +51,9 @@ int main(void) } for (i = 0; i < NCTX; i++) { - printf("talloc@%p %-40s %dkB\n", ctx[i], + printf("talloc@%p %-40s %ldkB\n", ctx[i], talloc_pool_name(ctx[i]), - talloc_pool_size(ctx[i]) >> 10); + (unsigned long)talloc_pool_size(ctx[i]) >> 10); } printf("%s", talloc_describe_all(ctx[0])); diff --git a/source3/lib/time.c b/source3/lib/time.c index 635ede9be2..faca2cba87 100644 --- a/source3/lib/time.c +++ b/source3/lib/time.c @@ -465,10 +465,9 @@ void unix_to_nt_time_abs(NTTIME *nt, time_t t) nt->low=~nt->low; } - /**************************************************************************** -take an NTTIME structure, containing high / low time. convert to unix time. -lkclXXXX this may need 2 SIVALs not a memcpy. we'll see... +take a Unix time and convert to an NTTIME structure and place in buffer +pointed to by p. ****************************************************************************/ void put_long_date(char *p,time_t t) { diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c index f552b38e67..d93f39696f 100644 --- a/source3/lib/util_str.c +++ b/source3/lib/util_str.c @@ -697,7 +697,7 @@ char *StrnCpy_fn(const char *fn, int line,char *dest,const char *src,size_t n) if (!dest) { DEBUG(0,("ERROR: NULL dest in StrnCpy, called from [%s][%d]\n", fn, line)); - return NULL; + return(NULL); } if (!src) { @@ -1196,7 +1196,7 @@ char *strchr_m(const char *src, char c) for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) { if (*s == c) - return s; + return (char *)s; } if (!*s) @@ -1244,7 +1244,7 @@ char *strrchr_m(const char *s, char c) break; } /* No - we have a match ! */ - return cp; + return (char *)cp; } } while (cp-- != s); if (!got_mb) diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c index 5122803597..1ab71c6ee5 100644 --- a/source3/libads/sasl.c +++ b/source3/libads/sasl.c @@ -124,13 +124,13 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip { DATA_BLOB blob; struct berval cred, *scred; - unsigned char sk[16]; + DATA_BLOB session_key; int rc; - blob = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, sk); + rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key); - if (!blob.data) { - return ADS_ERROR(LDAP_OPERATIONS_ERROR); + if (rc) { + return ADS_ERROR_KRB5(rc); } /* now send the auth packet and we should be done */ @@ -140,6 +140,7 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); data_blob_free(&blob); + data_blob_free(&session_key); return ADS_ERROR(rc); } @@ -166,6 +167,8 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) blob = data_blob(scred->bv_val, scred->bv_len); + ber_bvfree(scred); + #if 0 file_save("sasl_spnego.dat", blob.data, blob.length); #endif @@ -196,9 +199,13 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) status = ads_sasl_spnego_krb5_bind(ads, principal); if (ADS_ERR_OK(status)) return status; - if (ads_kinit_password(ads) == 0) { + + status = ADS_ERROR_KRB5(ads_kinit_password(ads)); + + if (ADS_ERR_OK(status)) { status = ads_sasl_spnego_krb5_bind(ads, principal); } + /* only fallback to NTLMSSP if allowed */ if (ADS_ERR_OK(status) || !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) { diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 28de7fc9f3..707a33881d 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -53,6 +53,13 @@ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user, if (passlen > sizeof(pword)-1) return False; + /* LANMAN servers predate NT status codes and Unicode and ignore those + smb flags so we must disable the corresponding default capabilities + that would otherwise cause the Unicode and NT Status flags to be + set (and even returned by the server) */ + + cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32); + /* if in share level security then don't send a password now */ if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) passlen = 0; @@ -493,19 +500,22 @@ static void use_in_memory_ccache(void) { Do a spnego/kerberos encrypted session setup. ****************************************************************************/ -static NTSTATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup) +static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup) { DATA_BLOB blob2, negTokenTarg; DATA_BLOB session_key_krb5; DATA_BLOB null_blob = data_blob(NULL, 0); - + int rc; + DEBUG(2,("Doing kerberos session setup\n")); /* generate the encapsulated kerberos5 ticket */ - negTokenTarg = spnego_gen_negTokenTarg(principal, 0, &session_key_krb5); + rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5); - if (!negTokenTarg.data) - return NT_STATUS_UNSUCCESSFUL; + if (rc) { + DEBUG(1, ("spnego_gen_negTokenTarg failed: %s\n", error_message(rc))); + return ADS_ERROR_KRB5(rc); + } #if 0 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length); @@ -524,10 +534,10 @@ static NTSTATUS cli_session_setup_kerberos(struct cli_state *cli, const char *pr if (cli_is_error(cli)) { if (NT_STATUS_IS_OK(cli_nt_error(cli))) { - return NT_STATUS_UNSUCCESSFUL; + return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); } } - return NT_STATUS_OK; + return ADS_ERROR_NT(cli_nt_error(cli)); } #endif /* HAVE_KRB5 */ @@ -537,7 +547,7 @@ static NTSTATUS cli_session_setup_kerberos(struct cli_state *cli, const char *pr ****************************************************************************/ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, - const char *pass, const char *workgroup) + const char *pass, const char *domain) { struct ntlmssp_state *ntlmssp_state; NTSTATUS nt_status; @@ -556,7 +566,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) { return nt_status; } - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, workgroup))) { + if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) { return nt_status; } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) { @@ -654,8 +664,8 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use Do a spnego encrypted session setup. ****************************************************************************/ -NTSTATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, - const char *pass, const char *workgroup) +ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, + const char *pass, const char *domain) { char *principal; char *OIDs[ASN1_MAX_OIDS]; @@ -682,7 +692,7 @@ NTSTATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, reply */ if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) { data_blob_free(&blob); - return NT_STATUS_INVALID_PARAMETER; + return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } data_blob_free(&blob); @@ -712,11 +722,11 @@ NTSTATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, if (ret){ DEBUG(0, ("Kinit failed: %s\n", error_message(ret))); - return NT_STATUS_LOGON_FAILURE; + return ADS_ERROR_KRB5(ret); } } - return cli_session_setup_kerberos(cli, principal, workgroup); + return cli_session_setup_kerberos(cli, principal, domain); } #endif @@ -724,7 +734,7 @@ NTSTATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, ntlmssp: - return cli_session_setup_ntlmssp(cli, user, pass, workgroup); + return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, user, pass, domain)); } /**************************************************************************** @@ -805,9 +815,9 @@ BOOL cli_session_setup(struct cli_state *cli, /* if the server supports extended security then use SPNEGO */ if (cli->capabilities & CAP_EXTENDED_SECURITY) { - NTSTATUS nt_status; - if (!NT_STATUS_IS_OK(nt_status = cli_session_setup_spnego(cli, user, pass, workgroup))) { - DEBUG(3, ("SPENGO login failed: %s\n", get_friendly_nt_error_msg(nt_status))); + ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, workgroup); + if (!ADS_ERR_OK(status)) { + DEBUG(3, ("SPENGO login failed: %s\n", ads_errstr(status))); return False; } return True; diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index 5568b5e033..15b244a83d 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -307,14 +307,14 @@ cleanup_princ: /* get a kerberos5 ticket for the given service */ -DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset, DATA_BLOB *session_key_krb5) +int cli_krb5_get_ticket(const char *principal, time_t time_offset, + DATA_BLOB *ticket, DATA_BLOB *session_key_krb5) { krb5_error_code retval; krb5_data packet; krb5_ccache ccdef; krb5_context context; krb5_auth_context auth_context = NULL; - DATA_BLOB ret; krb5_enctype enc_types[] = { #ifdef ENCTYPE_ARCFOUR_HMAC ENCTYPE_ARCFOUR_HMAC, @@ -356,17 +356,18 @@ DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset, DATA_BL get_krb5_smb_session_key(context, auth_context, session_key_krb5, False); - ret = data_blob(packet.data, packet.length); + *ticket = data_blob(packet.data, packet.length); + /* Hmm, heimdal dooesn't have this - what's the correct call? */ -/* krb5_free_data_contents(context, &packet); */ - krb5_free_context(context); - return ret; +#ifdef HAVE_KRB5_FREE_DATA_CONTENTS + krb5_free_data_contents(context, &packet); +#endif failed: if ( context ) krb5_free_context(context); - return data_blob(NULL, 0); + return retval; } BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote) @@ -410,10 +411,11 @@ failed: #else /* HAVE_KRB5 */ /* this saves a few linking headaches */ -DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset, DATA_BLOB *session_key_krb5) - { +int cli_krb5_get_ticket(const char *principal, time_t time_offset, + DATA_BLOB *ticket, DATA_BLOB *session_key_krb5) +{ DEBUG(0,("NO KERBEROS SUPPORT\n")); - return data_blob(NULL, 0); - } + return 1; +} #endif diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index 92543736ff..e6cadc466c 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -323,27 +323,30 @@ BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2]) generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY kerberos session setup */ -DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset, DATA_BLOB *session_key_krb5) +int spnego_gen_negTokenTarg(const char *principal, int time_offset, + DATA_BLOB *targ, + DATA_BLOB *session_key_krb5) { - DATA_BLOB tkt, tkt_wrapped, targ; + int retval; + DATA_BLOB tkt, tkt_wrapped; const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL}; /* get a kerberos ticket for the service and extract the session key */ - tkt = cli_krb5_get_ticket(principal, time_offset, session_key_krb5); + retval = cli_krb5_get_ticket(principal, time_offset, &tkt, session_key_krb5); - if (tkt.data == NULL) - return tkt; + if (retval) + return retval; /* wrap that up in a nice GSS-API wrapping */ tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ); /* and wrap that in a shiny SPNEGO wrapper */ - targ = gen_negTokenTarg(krb_mechs, tkt_wrapped); + *targ = gen_negTokenTarg(krb_mechs, tkt_wrapped); data_blob_free(&tkt_wrapped); data_blob_free(&tkt); - return targ; + return retval; } diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index c7cc4848b7..83902971b0 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -884,6 +884,40 @@ static BOOL resolve_hosts(const char *name, int name_type, */ struct hostent *hp; + if ( name_type != 0x20 && name_type != 0x0) { + DEBUG(5, ("resolve_hosts: not appropriate for name type <0x%x>\n", name_type)); + return False; + } + + *return_iplist = NULL; + *return_count = 0; + + DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x%x>\n", name, name_type)); + + if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) { + struct in_addr return_ip; + putip((char *)&return_ip,(char *)hp->h_addr); + *return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service)); + if(*return_iplist == NULL) { + DEBUG(3,("resolve_hosts: malloc fail !\n")); + return False; + } + (*return_iplist)->ip = return_ip; + (*return_iplist)->port = PORT_NONE; + *return_count = 1; + return True; + } + return False; +} + +/******************************************************** + Resolve via "ADS" method. +*********************************************************/ + +static BOOL resolve_ads(const char *name, int name_type, + struct ip_service **return_iplist, int *return_count) +{ + #ifdef HAVE_ADS if ( name_type == 0x1c ) { int count, i = 0; @@ -935,28 +969,11 @@ static BOOL resolve_hosts(const char *name, int name_type, *return_count = i; return True; - } + } else #endif /* HAVE_ADS */ - - *return_iplist = NULL; - *return_count = 0; - - DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name)); - - if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) { - struct in_addr return_ip; - putip((char *)&return_ip,(char *)hp->h_addr); - *return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service)); - if(*return_iplist == NULL) { - DEBUG(3,("resolve_hosts: malloc fail !\n")); - return False; - } - (*return_iplist)->ip = return_ip; - (*return_iplist)->port = PORT_NONE; - *return_count = 1; - return True; + { + return False; } - return False; } /******************************************************************* @@ -1034,14 +1051,17 @@ static BOOL internal_resolve_name(const char *name, int name_type, while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) { if((strequal(tok, "host") || strequal(tok, "hosts"))) { - /* deal with 0x20 & 0x1c names here. The latter will result - in a SRV record lookup for _ldap._tcp. if we are using - 'security = ads' */ - if ( name_type==0x20 || name_type == 0x1c ) { - if (resolve_hosts(name, name_type, return_iplist, return_count)) { - result = True; - goto done; - } + if (resolve_hosts(name, name_type, return_iplist, return_count)) { + result = True; + goto done; + } + } else if(strequal( tok, "ads")) { + /* deal with 0x1c names here. This will result in a + SRV record lookup for _ldap._tcp. if we + are using 'security = ads' */ + if (resolve_ads(name, name_type, return_iplist, return_count)) { + result = True; + goto done; } } else if(strequal( tok, "lmhosts")) { if (resolve_lmhosts(name, name_type, return_iplist, return_count)) { @@ -1207,14 +1227,14 @@ BOOL get_pdc_ip(const char *domain, struct in_addr *ip) /********************************************************************* small wrapper function to get the DC list and sort it if neccessary *********************************************************************/ -BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *count, BOOL dns_only ) +BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *count, BOOL ads_only ) { BOOL ordered; DEBUG(8,("get_sorted_dc_list: attempting lookup using [%s]\n", - (dns_only ? "hosts" : lp_name_resolve_order()))); + (ads_only ? "ads" : lp_name_resolve_order()))); - if ( !get_dc_list(domain, ip_list, count, dns_only, &ordered) ) + if ( !get_dc_list(domain, ip_list, count, ads_only, &ordered) ) return False; /* only sort if we don't already have an ordered list */ @@ -1230,11 +1250,11 @@ BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *c *********************************************************/ BOOL get_dc_list(const char *domain, struct ip_service **ip_list, - int *count, BOOL dns_only, int *ordered) + int *count, BOOL ads_only, int *ordered) { /* defined the name resolve order to internal_name_resolve() only used for looking up 0x1c names */ - const char *resolve_oder = (dns_only ? "hosts" : lp_name_resolve_order()); + const char *resolve_oder = (ads_only ? "ads" : lp_name_resolve_order()); *ordered = False; diff --git a/source3/locking/locking.c b/source3/locking/locking.c index d645a2fffb..c3abd63818 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -361,7 +361,7 @@ void unlock_share_entry(connection_struct *conn, } /******************************************************************* - Lock a hash bucket entry. Use an fsp for convenience. + Lock a hash bucket entry. use a fsp for convenience ******************************************************************/ BOOL lock_share_entry_fsp(files_struct *fsp) @@ -370,7 +370,7 @@ BOOL lock_share_entry_fsp(files_struct *fsp) } /******************************************************************* - Unlock a hash bucket entry. Use an fsp for convenience. + Unlock a hash bucket entry. ******************************************************************/ void unlock_share_entry_fsp(files_struct *fsp) diff --git a/source3/nmbd/nmbd_processlogon.c b/source3/nmbd/nmbd_processlogon.c index fc66e0d6b4..728796ea21 100644 --- a/source3/nmbd/nmbd_processlogon.c +++ b/source3/nmbd/nmbd_processlogon.c @@ -255,7 +255,7 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n", q = ALIGN4(q, buf); } - DEBUG(3,("process_logon_packet: len = %d PTR_DIFF(q, buf) = %d\n", len, PTR_DIFF(q, buf) )); + DEBUG(3,("process_logon_packet: len = %d PTR_DIFF(q, buf) = %ld\n", len, (unsigned long)PTR_DIFF(q, buf) )); if (len - PTR_DIFF(q, buf) > 8) { /* with NT5 clients we can sometimes diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c index 7d25524f8e..c7dc89d43f 100644 --- a/source3/nsswitch/wbinfo.c +++ b/source3/nsswitch/wbinfo.c @@ -298,18 +298,20 @@ static BOOL wbinfo_domain_info(const char *domain_name) /* Display response */ - d_printf("Name : %s\n", response.data.domain_info.name); - d_printf("Alt_Name: %s\n", response.data.domain_info.alt_name); + d_printf("Name : %s\n", response.data.domain_info.name); + d_printf("Alt_Name : %s\n", response.data.domain_info.alt_name); - d_printf("SID : %s\n", response.data.domain_info.sid); + d_printf("SID : %s\n", response.data.domain_info.sid); - d_printf("Native : %s\n", + d_printf("Active Directory : %s\n", + response.data.domain_info.active_directory ? "Yes" : "No"); + d_printf("Native : %s\n", response.data.domain_info.native_mode ? "Yes" : "No"); - d_printf("Primary : %s\n", + d_printf("Primary : %s\n", response.data.domain_info.primary ? "Yes" : "No"); - d_printf("Sequence: %d\n", response.data.domain_info.sequence_number); + d_printf("Sequence : %d\n", response.data.domain_info.sequence_number); return True; } @@ -909,14 +911,14 @@ static void wbinfo_get_auth_user(void) char *user, *domain, *password; /* Lift data from secrets file */ + + secrets_fetch_ipc_userpass(&user, &domain, &password); - secrets_init(); - - user = secrets_fetch(SECRETS_AUTH_USER, NULL); - domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL); - password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL); + if ((!user || !*user) && (!domain || !*domain ) && (!password || !*password)){ - if (!user && !domain && !password) { + SAFE_FREE(user); + SAFE_FREE(domain); + SAFE_FREE(password); d_printf("No authorised user configured\n"); return; } diff --git a/source3/nsswitch/winbind_nss_freebsd.c b/source3/nsswitch/winbind_nss_freebsd.c new file mode 100644 index 0000000000..b73a4ce44f --- /dev/null +++ b/source3/nsswitch/winbind_nss_freebsd.c @@ -0,0 +1,81 @@ +/* + Unix SMB/CIFS implementation. + + AIX loadable authentication module, providing identification + routines against Samba winbind/Windows NT Domain + + Copyright (C) Aaron Collins 2003 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "winbind_client.h" + +/* Make sure that the module gets registered needed by freebsd 5.1 */ + +extern enum nss_status _nss_winbind_getgrent_r(struct group *, char *, size_t, + int *); +extern enum nss_status _nss_winbind_getgrnam_r(const char *, struct group *, + char *, size_t, int *); +extern enum nss_status _nss_winbind_getgrgid_r(gid_t gid, struct group *, char *, + size_t, int *); +extern enum nss_status _nss_winbind_setgrent(void); +extern enum nss_status _nss_winbind_endgrent(void); + +extern enum nss_status _nss_winbind_getpwent_r(struct passwd *, char *, size_t, + int *); +extern enum nss_status _nss_winbind_getpwnam_r(const char *, struct passwd *, + char *, size_t, int *); +extern enum nss_status _nss_winbind_getpwuid_r(gid_t gid, struct passwd *, char *, + size_t, int *); +extern enum nss_status _nss_winbind_setpwent(void); +extern enum nss_status _nss_winbind_endpwent(void); + +NSS_METHOD_PROTOTYPE(__nss_compat_getgrnam_r); +NSS_METHOD_PROTOTYPE(__nss_compat_getgrgid_r); +NSS_METHOD_PROTOTYPE(__nss_compat_getgrent_r); +NSS_METHOD_PROTOTYPE(__nss_compat_setgrent); +NSS_METHOD_PROTOTYPE(__nss_compat_endgrent); + +NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam_r); +NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid_r); +NSS_METHOD_PROTOTYPE(__nss_compat_getpwent_r); +NSS_METHOD_PROTOTYPE(__nss_compat_setpwent); +NSS_METHOD_PROTOTYPE(__nss_compat_endpwent); + +static ns_mtab methods[] = { +{ NSDB_GROUP, "getgrnam_r", __nss_compat_getgrnam_r, _nss_winbind_getgrnam_r }, +{ NSDB_GROUP, "getgrgid_r", __nss_compat_getgrgid_r, _nss_winbind_getgrgid_r }, +{ NSDB_GROUP, "getgrent_r", __nss_compat_getgrent_r, _nss_winbind_getgrent_r }, +{ NSDB_GROUP, "endgrent", __nss_compat_setgrent, _nss_winbind_setgrent }, +{ NSDB_GROUP, "setgrent", __nss_compat_endgrent, _nss_winbind_endgrent }, + +{ NSDB_PASSWD, "getpwnam_r", __nss_compat_getpwnam_r, _nss_winbind_getpwnam_r }, +{ NSDB_PASSWD, "getpwuid_r", __nss_compat_getpwuid_r, _nss_winbind_getpwuid_r }, +{ NSDB_PASSWD, "getpwent_r", __nss_compat_getpwent_r, _nss_winbind_getpwent_r }, +{ NSDB_PASSWD, "endpwent", __nss_compat_setpwent, _nss_winbind_setpwent }, +{ NSDB_PASSWD, "setpwent", __nss_compat_endpwent, _nss_winbind_endpwent }, + +}; + +ns_mtab * +nss_module_register(const char *source, unsigned int *mtabsize, + nss_module_unregister_fn *unreg) +{ + *mtabsize = sizeof(methods)/sizeof(methods[0]); + *unreg = NULL; + return (methods); +} diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index 4c03522461..3124ef6378 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -935,6 +935,8 @@ int main(int argc, char **argv) netsamlogon_cache_init(); /* Non-critical */ + init_domain_list(); + /* Loop waiting for requests */ process_loop(); diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 5dbe422bc1..7c8e6256e1 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -95,7 +95,8 @@ struct winbindd_domain { fstring alt_name; /* alt Domain name (if any) */ DOM_SID sid; /* SID for this domain */ BOOL native_mode; /* is this a win2k domain in native mode ? */ - BOOL primary; /* is this our primary domain ? */ + BOOL active_directory; /* is this a win2k active directory ? */ + BOOL primary; /* is this our primary domain ? */ /* Lookup methods for this domain (LDAP or RPC) */ struct winbindd_methods *methods; diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c index ec93d494d0..e6b857f406 100644 --- a/source3/nsswitch/winbindd_ads.c +++ b/source3/nsswitch/winbindd_ads.c @@ -112,7 +112,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, goto done; } - rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs); + rc = ads_search_retry(ads, &res, "(objectClass=user)", attrs); if (!ADS_ERR_OK(rc) || !res) { DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc))); goto done; diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index a3c1706b75..8dec89a6aa 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/nsswitch/winbindd_cache.c @@ -107,12 +107,14 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain) case SEC_ADS: { extern struct winbindd_methods ads_methods; /* always obey the lp_security parameter for our domain */ - if ( strequal(lp_realm(), domain->alt_name) || strequal(lp_workgroup(), domain->name) ) { + if (domain->primary) { domain->backend = &ads_methods; break; } - if ( domain->native_mode ) { + /* if it have either of the indications of ADS, + use ads_methods */ + if ( domain->active_directory || domain->native_mode ) { domain->backend = &ads_methods; break; } diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 2b561be31d..44fc06fe54 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -174,16 +174,19 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i if ((lp_security() == SEC_ADS) && (new_conn->cli->protocol >= PROTOCOL_NT1 && new_conn->cli->capabilities & CAP_EXTENDED_SECURITY)) { + ADS_STATUS ads_status; new_conn->cli->use_kerberos = True; DEBUG(5, ("connecting to %s from %s with kerberos principal [%s]\n", new_conn->controller, global_myname(), machine_krb5_principal)); - result = NT_STATUS_OK; - - if (!NT_STATUS_IS_OK(result = cli_session_setup_spnego(new_conn->cli, machine_krb5_principal, - machine_password, - lp_workgroup()))) { - DEBUG(4,("failed kerberos session setup with %s\n", nt_errstr(result))); + ads_status = cli_session_setup_spnego(new_conn->cli, machine_krb5_principal, + machine_password, + lp_workgroup()); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("failed kerberos session setup with %s\n", ads_errstr(ads_status))); + result = ads_ntstatus(ads_status); + } else { + result = NT_STATUS_OK; } } new_conn->cli->use_kerberos = False; @@ -405,46 +408,116 @@ static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const } /********************************************************************************** + We can 'sense' certain things about the DC by it's replies to certain questions. + + This tells us if this particular remote server is Active Directory, and if it is + native mode. **********************************************************************************/ -BOOL cm_check_for_native_mode_win2k( struct winbindd_domain *domain ) +void set_dc_type_and_flags( struct winbindd_domain *domain ) { NTSTATUS result; struct winbindd_cm_conn conn; DS_DOMINFO_CTR ctr; - BOOL ret = False; + TALLOC_CTX *mem_ctx = NULL; ZERO_STRUCT( conn ); ZERO_STRUCT( ctr ); + domain->native_mode = False; + domain->active_directory = False; if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) { - DEBUG(5, ("cm_check_for_native_mode_win2k: Could not open a connection to %s for PIPE_LSARPC (%s)\n", + DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n", domain->name, nt_errstr(result))); - return False; + return; } if ( conn.cli ) { if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli, conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) { - ret = False; goto done; } } if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) ) - ret = True; + domain->native_mode = True; -done: + /* Cheat - shut down the DS pipe, and open LSA */ + + cli_nt_session_close(conn.cli); + + if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) { + char *domain_name = NULL; + char *dns_name = NULL; + DOM_SID *dom_sid = NULL; + + mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name); + if (!mem_ctx) { + DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n")); + return; + } + + result = cli_lsa_open_policy2(conn.cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &conn.pol); + + if (NT_STATUS_IS_OK(result)) { + /* This particular query is exactly what Win2k clients use + to determine that the DC is active directory */ + result = cli_lsa_query_info_policy2(conn.cli, mem_ctx, + &conn.pol, + 12, &domain_name, + &dns_name, NULL, + NULL, &dom_sid); + } + + if (NT_STATUS_IS_OK(result)) { + if (domain_name) + fstrcpy(domain->name, domain_name); + + if (dns_name) + fstrcpy(domain->alt_name, dns_name); + if (dom_sid) + sid_copy(&domain->sid, dom_sid); + + domain->active_directory = True; + } else { + + result = cli_lsa_open_policy(conn.cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &conn.pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = cli_lsa_query_info_policy(conn.cli, mem_ctx, + &conn.pol, 5, &domain_name, + &dom_sid); + + if (NT_STATUS_IS_OK(result)) { + if (domain_name) + fstrcpy(domain->name, domain_name); + + if (dom_sid) + sid_copy(&domain->sid, dom_sid); + } + } + } + +done: + /* close the connection; no other cals use this pipe and it is called only on reestablishing the domain list --jerry */ - + if ( conn.cli ) cli_shutdown( conn.cli ); - return ret; + talloc_destroy(mem_ctx); + + return; } diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index 180a3db8e2..b31dc92b38 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -106,7 +106,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, *num_gr_mem = 0; if ( !((group_name_type==SID_NAME_DOM_GRP) || - ((group_name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) ) + ((group_name_type==SID_NAME_ALIAS) && domain->primary)) ) { DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n", sid_to_string(sid_string, group_sid), domain->name, @@ -152,15 +152,10 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, occur in Universal groups on a Windows 2000 native mode server. */ - if (name_types[i] != SID_NAME_USER) { - DEBUG(3, ("name %s isn't a domain user\n", the_name)); - continue; - } + /* make sure to allow machine accounts */ - /* Don't bother with machine accounts */ - - if (the_name[strlen(the_name) - 1] == '$') { - DEBUG(10, ("%s is machine account\n", the_name)); + if (name_types[i] != SID_NAME_USER && name_types[i] != SID_NAME_COMPUTER) { + DEBUG(3, ("name %s isn't a domain user\n", the_name)); continue; } @@ -265,22 +260,20 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) return WINBINDD_OK; } - /* should we deal with users for our domain? */ - - if ( lp_winbind_trusted_domains_only() && strequal(name_domain, lp_workgroup())) { - DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n", - name_domain, name_group)); - return WINBINDD_ERROR; - } - - /* Get info for the domain */ if ((domain = find_domain_from_name(name_domain)) == NULL) { - DEBUG(0, ("could not get domain sid for domain %s\n", + DEBUG(3, ("could not get domain sid for domain %s\n", name_domain)); return WINBINDD_ERROR; } + /* should we deal with users for our domain? */ + + if ( lp_winbind_trusted_domains_only() && domain->primary) { + DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n", + name_domain, name_group)); + return WINBINDD_ERROR; + } /* Get rid and name type from name */ @@ -292,7 +285,7 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) } if ( !((name_type==SID_NAME_DOM_GRP) || - ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) ) + ((name_type==SID_NAME_ALIAS) && domain->primary)) ) { DEBUG(1, ("name '%s' is not a local or domain group: %d\n", name_group, name_type)); @@ -383,7 +376,7 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state) } if ( !((name_type==SID_NAME_DOM_GRP) || - ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) ) + ((name_type==SID_NAME_ALIAS) && domain->primary) )) { DEBUG(1, ("name '%s' is not a local or domain group: %d\n", group_name, name_type)); @@ -441,7 +434,7 @@ enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state) are a member of a Samba domain */ if ( (IS_DC || lp_winbind_trusted_domains_only()) - && strequal(domain->name, lp_workgroup()) ) + && domain->primary ) { continue; } @@ -547,7 +540,7 @@ static BOOL get_sam_group_entries(struct getent_state *ent) and are not using LDAP to get the groups */ if ( lp_security() != SEC_ADS && domain->native_mode - && strequal(lp_workgroup(), domain->name) ) + && domain->primary ) { DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n")); @@ -887,7 +880,7 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) extra_data[extra_data_len++] = ','; } - free(groups.sam_entries); + SAFE_FREE(groups.sam_entries); } /* Assign extra_data fields in response structure */ @@ -938,21 +931,22 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) /* Parse domain and username */ parse_domain_user(state->request.data.username, - name_domain, name_user); - - /* bail if there is no domain */ + name_domain, name_user); - if ( !*name_domain ) - goto done; - /* Get info for the domain */ if ((domain = find_domain_from_name(name_domain)) == NULL) { - DEBUG(0, ("could not find domain entry for domain %s\n", + DEBUG(7, ("could not find domain entry for domain %s\n", name_domain)); goto done; } + if ( domain->primary && lp_winbind_trusted_domains_only()) { + DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getgroups() for %s\\%s.\n", + name_domain, name_user)); + return WINBINDD_ERROR; + } + /* Get rid and name type from name. The following costs 1 packet */ if (!winbindd_lookup_sid_by_name(domain, name_user, &user_sid, @@ -961,7 +955,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) goto done; } - if (name_type != SID_NAME_USER) { + if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) { DEBUG(1, ("name '%s' is not a user name: %d\n", name_user, name_type)); goto done; @@ -1000,7 +994,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) in a win2k native mode domain. */ if ( !((sid_type==SID_NAME_DOM_GRP) || - ((sid_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) ) + ((sid_type==SID_NAME_ALIAS) && domain->primary)) ) { DEBUG(10, ("winbindd_getgroups: sid type %d " "for %s is not a domain group\n", @@ -1127,7 +1121,7 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state) sid_string_static(&user_sid))); goto done; } - + status = domain->methods->lookup_usergroups(domain, mem_ctx, &user_sid, &num_groups, &user_grpsids); diff --git a/source3/nsswitch/winbindd_misc.c b/source3/nsswitch/winbindd_misc.c index 08b5be827d..18478992f3 100644 --- a/source3/nsswitch/winbindd_misc.c +++ b/source3/nsswitch/winbindd_misc.c @@ -36,7 +36,6 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat int num_retries = 0; struct cli_state *cli; uint32 sec_channel_type; - const char *contact_domain_name = NULL; struct winbindd_domain *contact_domain; DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid)); @@ -51,18 +50,10 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat } - /* use the realm name if appropriate and possible */ - - if ( lp_security() == SEC_ADS ) - contact_domain_name = lp_realm(); - - if ( !contact_domain_name || !*contact_domain_name ) - contact_domain_name = lp_workgroup(); - - contact_domain = find_domain_from_name(contact_domain_name); + contact_domain = find_our_domain(); if (!contact_domain) { result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - DEBUG(1, ("%s is not a trusted domain\n", contact_domain_name)); + DEBUG(1, ("Cannot find our own domain!\n")); goto done; } @@ -132,7 +123,7 @@ enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state /* Skip own domain */ - if (strequal(domain->name, lp_workgroup())) continue; + if (domain->primary) continue; /* Add domain to list */ @@ -232,6 +223,7 @@ enum winbindd_result winbindd_domain_info(struct winbindd_cli_state *state) sid_string_static(&domain->sid)); state->response.data.domain_info.native_mode = domain->native_mode; + state->response.data.domain_info.active_directory = domain->active_directory; state->response.data.domain_info.primary = domain->primary; state->response.data.domain_info.sequence_number = diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index 0dd00e9b39..0d110b8afa 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -36,7 +36,7 @@ /* Update this when you change the interface. */ -#define WINBIND_INTERFACE_VERSION 8 +#define WINBIND_INTERFACE_VERSION 9 /* Socket commands */ @@ -272,6 +272,7 @@ struct winbindd_response { fstring alt_name; fstring sid; BOOL native_mode; + BOOL active_directory; BOOL primary; uint32 sequence_number; } domain_info; diff --git a/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c index f619aa3564..21e0c3092e 100644 --- a/source3/nsswitch/winbindd_rpc.c +++ b/source3/nsswitch/winbindd_rpc.c @@ -950,7 +950,8 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid) NTSTATUS result = NT_STATUS_UNSUCCESSFUL; TALLOC_CTX *mem_ctx; CLI_POLICY_HND *hnd; - fstring level5_dom; + char *level5_dom; + DOM_SID *alloc_sid; int retry; DEBUG(3,("rpc: domain_sid\n")); @@ -965,9 +966,17 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid) goto done; result = cli_lsa_query_info_policy(hnd->cli, mem_ctx, - &hnd->pol, 0x05, level5_dom, sid); + &hnd->pol, 0x05, &level5_dom, &alloc_sid); } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1); + if (NT_STATUS_IS_OK(result)) { + if (alloc_sid) { + sid_copy(sid, alloc_sid); + } else { + result = NT_STATUS_NO_MEMORY; + } + } + done: talloc_destroy(mem_ctx); return result; diff --git a/source3/nsswitch/winbindd_sid.c b/source3/nsswitch/winbindd_sid.c index 7c4c8d804a..9fbf47046d 100644 --- a/source3/nsswitch/winbindd_sid.c +++ b/source3/nsswitch/winbindd_sid.c @@ -152,7 +152,7 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) DOM_SID sid2; uint32 rid; - domain = find_domain_from_name( lp_workgroup() ); + domain = find_our_domain(); if ( !domain ) { DEBUG(0,("winbindd_sid_to_uid: can't find my own domain!\n")); return WINBINDD_ERROR; @@ -244,7 +244,7 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) uint32 rid; unid_t id; - domain = find_domain_from_name( lp_workgroup() ); + domain = find_our_domain(); if ( !domain ) { DEBUG(0,("winbindd_sid_to_uid: can't find my own domain!\n")); return WINBINDD_ERROR; @@ -341,7 +341,7 @@ enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state) if ( !(pw = getpwuid(state->request.data.uid)) ) return WINBINDD_ERROR; - if ( !(domain = find_domain_from_name(lp_workgroup())) ) { + if ( !(domain = find_our_domain()) ) { DEBUG(0,("winbindd_uid_to_sid: can't find my own domain!\n")); return WINBINDD_ERROR; } @@ -411,7 +411,7 @@ enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state) if ( !(grp = getgrgid(state->request.data.gid)) ) return WINBINDD_ERROR; - if ( !(domain = find_domain_from_name(lp_workgroup())) ) { + if ( !(domain = find_our_domain()) ) { DEBUG(0,("winbindd_uid_to_sid: can't find my own domain!\n")); return WINBINDD_ERROR; } diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 903a2a8bfa..d08377c888 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -37,7 +37,8 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name, char *full_name, struct winbindd_pw *pw) { fstring output_username; - pstring homedir; + char *homedir; + char *shell; fstring sid_string; if (!pw || !dom_name || !user_name) @@ -72,24 +73,32 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name, shell. */ /* The substitution of %U and %D in the 'template homedir' is done - by lp_string() calling standard_sub_basic(). */ + by alloc_sub_specified() below. */ - fstrcpy(current_user_info.smb_name, user_name); - sub_set_smb_name(user_name); fstrcpy(current_user_info.domain, dom_name); - pstrcpy(homedir, lp_template_homedir()); + homedir = alloc_sub_specified(lp_template_homedir(), user_name, dom_name, pw->pw_uid, pw->pw_gid); + + if (!homedir) + return False; safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1); - safe_strcpy(pw->pw_shell, lp_template_shell(), + SAFE_FREE(homedir); + + shell = alloc_sub_specified(lp_template_shell(), user_name, dom_name, pw->pw_uid, pw->pw_gid); + + if (!shell) + return False; + + safe_strcpy(pw->pw_shell, shell, sizeof(pw->pw_shell) - 1); /* Password - set to "x" as we can't generate anything useful here. Authentication can be done using the pam_winbind module. */ safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1); - + return True; } @@ -115,7 +124,7 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) /* Parse domain and username */ parse_domain_user(state->request.data.username, - name_domain, name_user); + name_domain, name_user); /* if this is our local domain (or no domain), the do a local tdb search */ @@ -131,17 +140,17 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) /* should we deal with users for our domain? */ - if ( lp_winbind_trusted_domains_only() && strequal(name_domain, lp_workgroup())) { - DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n", - name_domain, name_user)); - return WINBINDD_ERROR; - } - if ((domain = find_domain_from_name(name_domain)) == NULL) { DEBUG(5, ("no such domain: %s\n", name_domain)); return WINBINDD_ERROR; } + if ( domain->primary && lp_winbind_trusted_domains_only()) { + DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n", + name_domain, name_user)); + return WINBINDD_ERROR; + } + /* Get rid and name type from name */ if (!winbindd_lookup_sid_by_name(domain, name_user, &user_sid, &name_type)) { @@ -149,15 +158,13 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) return WINBINDD_ERROR; } - if (name_type != SID_NAME_USER) { + if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) { DEBUG(1, ("name '%s' is not a user name: %d\n", name_user, name_type)); return WINBINDD_ERROR; } - /* Get some user info. Split the user rid from the sid obtained - from the winbind_lookup_by_name() call and use it in a - winbind_lookup_userinfo() */ + /* Get some user info. */ if (!(mem_ctx = talloc_init("winbindd_getpwnam([%s]\\[%s])", name_domain, name_user))) { @@ -530,15 +537,6 @@ enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state) name_list = ent->sam_entries; - /* Skip machine accounts */ - - if (name_list[ent->sam_entry_index]. - name[strlen(name_list[ent->sam_entry_index].name) - 1] - == '$') { - ent->sam_entry_index++; - continue; - } - /* Lookup user info */ result = winbindd_fill_pwent( diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index 4cc43e85d6..076ab1a2fc 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -49,6 +49,14 @@ static const fstring name_deadbeef = ""; static struct winbindd_domain *_domain_list; +/** + When was the last scan of trusted domains done? + + 0 == not ever +*/ + +static time_t last_trustdom_scan; + struct winbindd_domain *domain_list(void) { /* Initialise list */ @@ -83,6 +91,7 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const { struct winbindd_domain *domain; const char *alternative_name = NULL; + static const DOM_SID null_sid; /* ignore alt_name if we are not in an AD domain */ @@ -103,6 +112,13 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const return domain; } } + if (sid) { + if (sid_equal(sid, &null_sid) ) { + + } else if (sid_equal(sid, &domain->sid)) { + return domain; + } + } } /* Create new domain entry */ @@ -133,12 +149,14 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const sid_copy(&domain->sid, sid); } - /* see if this is a native mode win2k domain */ + /* set flags about native_mode, active_directory */ - domain->native_mode = cm_check_for_native_mode_win2k( domain ); + set_dc_type_and_flags( domain ); - DEBUG(3,("add_trusted_domain: %s is a %s mode domain\n", domain->name, - domain->native_mode ? "native" : "mixed (or NT4)" )); + DEBUG(3,("add_trusted_domain: %s is an %s %s domain\n", domain->name, + domain->active_directory ? "ADS" : "NT4", + domain->native_mode ? "native mode" : + ((domain->active_directory && !domain->native_mode) ? "mixed mode" : ""))); /* Link to domain list */ DLIST_ADD(_domain_list, domain); @@ -156,13 +174,12 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const void rescan_trusted_domains( void ) { - static time_t last_scan; time_t now = time(NULL); struct winbindd_domain *mydomain = NULL; /* see if the time has come... */ - if ( (now > last_scan) && ((now-last_scan) < WINBINDD_RESCAN_FREQ) ) + if ( (now > last_trustdom_scan) && ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) ) return; if ( (mydomain = find_our_domain()) == NULL ) { @@ -174,7 +191,7 @@ void rescan_trusted_domains( void ) add_trusted_domains( mydomain ); - last_scan = now; + last_trustdom_scan = now; return; } @@ -200,7 +217,7 @@ void add_trusted_domains( struct winbindd_domain *domain ) return; } - DEBUG(1, ("scanning trusted domain list\n")); + DEBUG(5, ("scanning trusted domain list\n")); if (!(mem_ctx = talloc_init("init_domain_list"))) return; @@ -221,7 +238,7 @@ void add_trusted_domains( struct winbindd_domain *domain ) for(i = 0; i < num_domains; i++) { DEBUG(10,("Found domain %s\n", names[i])); add_trusted_domain(names[i], alt_names?alt_names[i]:NULL, - domain->methods, &dom_sids[i]); + domain->methods, &dom_sids[i]); /* if the SID was empty, we better set it now */ @@ -263,7 +280,7 @@ BOOL init_domain_list(void) /* Free existing list */ free_domain_list(); - /* Add ourselves as the first entry. It *must* be the first entry */ + /* Add ourselves as the first entry. */ domain = add_trusted_domain( lp_workgroup(), lp_realm(), &cache_methods, NULL); @@ -286,7 +303,9 @@ BOOL init_domain_list(void) /* do an initial scan for trusted domains */ add_trusted_domains(domain); - + + /* avoid rescanning this right away */ + last_trustdom_scan = time(NULL); return True; } @@ -364,10 +383,6 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, { NTSTATUS result; TALLOC_CTX *mem_ctx; - /* Don't bother with machine accounts */ - - if (name[strlen(name) - 1] == '$') - return False; mem_ctx = talloc_init("lookup_sid_by_name for %s\n", name); if (!mem_ctx) diff --git a/source3/nsswitch/wins.c b/source3/nsswitch/wins.c index 779d1b2c6c..100a103924 100644 --- a/source3/nsswitch/wins.c +++ b/source3/nsswitch/wins.c @@ -194,7 +194,7 @@ int lookup(nsd_file_t *rq) * response needs to be a string of the following format * ip_address[ ip_address]*\tname[ alias]* */ - if (strcasecmp(map,"hosts.byaddr") == 0) { + if (StrCaseCmp(map,"hosts.byaddr") == 0) { if ( status = lookup_byaddr_backend(key, &count)) { size = strlen(key) + 1; if (size > len) { @@ -222,7 +222,7 @@ int lookup(nsd_file_t *rq) response[strlen(response)-1] = '\n'; free(status); } - } else if (strcasecmp(map,"hosts.byname") == 0) { + } else if (StrCaseCmp(map,"hosts.byname") == 0) { if (ip_list = lookup_byname_backend(key, &count)) { for (i = count; i ; i--) { addr = inet_ntoa(ip_list[i-1]); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 67012ee087..a1fb90157c 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -217,6 +217,7 @@ typedef struct int change_notify_timeout; int map_to_guest; int min_passwd_length; + BOOL use_cracklib; int oplock_break_wait_time; int winbind_cache_time; int iLockSpinCount; @@ -749,6 +750,12 @@ static const struct enum_list enum_map_to_guest[] = { * Any parameter that does NOT have FLAG_ADVANCED will not disply at all * Set FLAG_SHARE and FLAG_PRINT to specifically display parameters in * respective views. + * + * NOTE2: Handling of duplicated (synonym) paramters: + * Only the first occurance of a parameter should be enabled by FLAG_BASIC + * and/or FLAG_ADVANCED. All duplicates following the first mention should be + * set to FLAG_HIDE. ie: Make you must place the parameter that has the preferred + * name first, and all synonyms must follow it with the FLAG_HIDE attribute. */ static struct parm_struct parm_table[] = { @@ -784,6 +791,7 @@ static struct parm_struct parm_table[] = { {"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL, NULL, FLAG_ADVANCED}, {"min passwd length", P_INTEGER, P_GLOBAL, &Globals.min_passwd_length, NULL, NULL, FLAG_ADVANCED}, {"min password length", P_INTEGER, P_GLOBAL, &Globals.min_passwd_length, NULL, NULL, FLAG_ADVANCED}, + {"use cracklib", P_BOOL, P_GLOBAL, &Globals.use_cracklib, NULL, NULL, FLAG_ADVANCED}, {"map to guest", P_ENUM, P_GLOBAL, &Globals.map_to_guest, NULL, enum_map_to_guest, FLAG_ADVANCED}, {"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL, NULL, FLAG_ADVANCED}, {"obey pam restrictions", P_BOOL, P_GLOBAL, &Globals.bObeyPamRestrictions, NULL, NULL, FLAG_ADVANCED}, @@ -1153,9 +1161,9 @@ static struct parm_struct parm_table[] = { {"enable rid algorithm", P_BOOL, P_GLOBAL, &Globals.bEnableRidAlgorithm, NULL, NULL, FLAG_DEPRECATED}, {"idmap backend", P_STRING, P_GLOBAL, &Globals.szIdmapBackend, NULL, NULL, FLAG_ADVANCED}, {"idmap uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED}, - {"winbind uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED}, + {"winbind uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_HIDE}, {"idmap gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_ADVANCED}, - {"winbind gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_ADVANCED}, + {"winbind gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_HIDE}, {"template primary group", P_STRING, P_GLOBAL, &Globals.szTemplatePrimaryGroup, NULL, NULL, FLAG_ADVANCED}, {"template homedir", P_STRING, P_GLOBAL, &Globals.szTemplateHomedir, NULL, NULL, FLAG_ADVANCED}, {"template shell", P_STRING, P_GLOBAL, &Globals.szTemplateShell, NULL, NULL, FLAG_ADVANCED}, @@ -1437,6 +1445,7 @@ static void init_globals(void) Globals.map_to_guest = 0; /* By Default, "Never" */ Globals.min_passwd_length = MINPASSWDLENGTH; /* By Default, 5. */ + Globals.use_cracklib = False; Globals.oplock_break_wait_time = 0; /* By Default, 0 msecs. */ Globals.enhanced_browsing = True; Globals.iLockSpinCount = 3; /* Try 3 times. */ @@ -1681,8 +1690,8 @@ FN_GLOBAL_STRING(lp_abort_shutdown_script, &Globals.szAbortShutdownScript) 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) -FN_GLOBAL_STRING(lp_template_homedir, &Globals.szTemplateHomedir) -FN_GLOBAL_STRING(lp_template_shell, &Globals.szTemplateShell) +FN_GLOBAL_CONST_STRING(lp_template_homedir, &Globals.szTemplateHomedir) +FN_GLOBAL_CONST_STRING(lp_template_shell, &Globals.szTemplateShell) FN_GLOBAL_CONST_STRING(lp_winbind_separator, &Globals.szWinbindSeparator) FN_GLOBAL_STRING(lp_acl_compatibility, &Globals.szAclCompat) FN_GLOBAL_BOOL(lp_winbind_enable_local_accounts, &Globals.bWinbindEnableLocalAccounts) @@ -1791,6 +1800,7 @@ FN_GLOBAL_INTEGER(lp_machine_password_timeout, &Globals.machine_password_timeout FN_GLOBAL_INTEGER(lp_change_notify_timeout, &Globals.change_notify_timeout) FN_GLOBAL_INTEGER(lp_map_to_guest, &Globals.map_to_guest) FN_GLOBAL_INTEGER(lp_min_passwd_length, &Globals.min_passwd_length) +FN_GLOBAL_BOOL(lp_use_cracklib, &Globals.use_cracklib) FN_GLOBAL_INTEGER(lp_oplock_break_wait_time, &Globals.oplock_break_wait_time) FN_GLOBAL_INTEGER(lp_lock_spin_count, &Globals.iLockSpinCount) FN_GLOBAL_INTEGER(lp_lock_sleep_time, &Globals.iLockSpinTime) diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index a5a2c29a8b..f9557cac42 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -3,6 +3,7 @@ Copyright (C) Andrew Tridgell 1992-2001 Copyright (C) Andrew Bartlett 2002 Copyright (C) Rafal Szczesniak 2002 + Copyright (C) Tim Potter 2001 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -790,3 +791,40 @@ BOOL secrets_fetch_afs_key(const char *cell, struct afs_key *result) return True; } + +/****************************************************************************** + When kerberos is not available, choose between anonymous or + authenticated connections. + + We need to use an authenticated connection if DCs have the + RestrictAnonymous registry entry set > 0, or the "Additional + restrictions for anonymous connections" set in the win2k Local + Security Policy. + + Caller to free() result in domain, username, password +*******************************************************************************/ +void secrets_fetch_ipc_userpass(char **username, char **domain, char **password) +{ + *username = secrets_fetch(SECRETS_AUTH_USER, NULL); + *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL); + *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL); + + if (*username && **username) { + + if (!*domain || !**domain) + *domain = smb_xstrdup(lp_workgroup()); + + if (!*password || !**password) + *password = smb_xstrdup(""); + + DEBUG(3, ("IPC$ connections done by user %s\\%s\n", + *domain, *username)); + + } else { + DEBUG(3, ("IPC$ connections done anonymously\n")); + *username = smb_xstrdup(""); + *domain = smb_xstrdup(""); + *password = smb_xstrdup(""); + } +} + diff --git a/source3/printing/notify.c b/source3/printing/notify.c index f2dd7d4f22..7750239630 100644 --- a/source3/printing/notify.c +++ b/source3/printing/notify.c @@ -20,6 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "includes.h" #include "printing.h" static TALLOC_CTX *send_ctx; diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c index 77719ffc52..f0096a17c2 100644 --- a/source3/printing/print_cups.c +++ b/source3/printing/print_cups.c @@ -18,6 +18,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "includes.h" #include "printing.h" #ifdef HAVE_CUPS diff --git a/source3/printing/print_generic.c b/source3/printing/print_generic.c index 1c847448da..9e0ea85bb9 100644 --- a/source3/printing/print_generic.c +++ b/source3/printing/print_generic.c @@ -18,6 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "includes.h" #include "printing.h" diff --git a/source3/printing/printing.c b/source3/printing/printing.c index 791c41fe69..bdcd950450 100644 --- a/source3/printing/printing.c +++ b/source3/printing/printing.c @@ -20,6 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "includes.h" #include "printing.h" /* Current printer interface */ diff --git a/source3/printing/printing_db.c b/source3/printing/printing_db.c index 1c7ac71353..0e0fb1b51d 100644 --- a/source3/printing/printing_db.c +++ b/source3/printing/printing_db.c @@ -20,6 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "includes.h" #include "printing.h" static struct tdb_print_db *print_db_head; diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index 0ec9beb1a4..40b83c5c0c 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/rpc_client/cli_lsarpc.c @@ -443,7 +443,7 @@ NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *pol, uint16 info_class, - fstring domain_name, DOM_SID *domain_sid) + char **domain_name, DOM_SID **domain_sid) { prs_struct qbuf, rbuf; LSA_Q_QUERY_INFO q; @@ -481,39 +481,40 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx, /* Return output parameters */ - ZERO_STRUCTP(domain_sid); - domain_name[0] = '\0'; - switch (info_class) { case 3: - if (r.dom.id3.buffer_dom_name != 0) { - unistr2_to_ascii(domain_name, - &r.dom.id3. - uni_domain_name, - sizeof (fstring) - 1); + if (domain_name && (r.dom.id3.buffer_dom_name != 0)) { + *domain_name = unistr2_tdup(mem_ctx, + &r.dom.id3. + uni_domain_name); } - if (r.dom.id3.buffer_dom_sid != 0) { - *domain_sid = r.dom.id3.dom_sid.sid; + if (domain_sid && (r.dom.id3.buffer_dom_sid != 0)) { + *domain_sid = talloc(mem_ctx, sizeof(**domain_sid)); + if (*domain_sid) { + sid_copy(*domain_sid, &r.dom.id3.dom_sid.sid); + } } break; case 5: - if (r.dom.id5.buffer_dom_name != 0) { - unistr2_to_ascii(domain_name, &r.dom.id5. - uni_domain_name, - sizeof (fstring) - 1); + if (domain_name && (r.dom.id5.buffer_dom_name != 0)) { + *domain_name = unistr2_tdup(mem_ctx, + &r.dom.id5. + uni_domain_name); } - if (r.dom.id5.buffer_dom_sid != 0) { - *domain_sid = r.dom.id5.dom_sid.sid; + if (domain_sid && (r.dom.id5.buffer_dom_sid != 0)) { + *domain_sid = talloc(mem_ctx, sizeof(**domain_sid)); + if (*domain_sid) { + sid_copy(*domain_sid, &r.dom.id5.dom_sid.sid); + } } - break; - + default: DEBUG(3, ("unknown info class %d\n", info_class)); break; @@ -536,10 +537,9 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx, NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *pol, uint16 info_class, - fstring domain_name, fstring dns_name, - fstring forest_name, - struct uuid *domain_guid, - DOM_SID *domain_sid) + char **domain_name, char **dns_name, + char **forest_name, struct uuid **domain_guid, + DOM_SID **domain_sid) { prs_struct qbuf, rbuf; LSA_Q_QUERY_INFO2 q; @@ -580,30 +580,37 @@ NTSTATUS cli_lsa_query_info_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx, /* Return output parameters */ - ZERO_STRUCTP(domain_sid); ZERO_STRUCTP(domain_guid); - domain_name[0] = '\0'; - if (r.info.dns_dom_info.hdr_nb_dom_name.buffer) { - unistr2_to_ascii(domain_name, - &r.info.dns_dom_info.uni_nb_dom_name, - sizeof(fstring) - 1); + if (domain_name && r.info.dns_dom_info.hdr_nb_dom_name.buffer) { + *domain_name = unistr2_tdup(mem_ctx, + &r.info.dns_dom_info + .uni_nb_dom_name); } - if (r.info.dns_dom_info.hdr_dns_dom_name.buffer) { - unistr2_to_ascii(dns_name, - &r.info.dns_dom_info.uni_dns_dom_name, - sizeof(fstring) - 1); + if (dns_name && r.info.dns_dom_info.hdr_dns_dom_name.buffer) { + *dns_name = unistr2_tdup(mem_ctx, + &r.info.dns_dom_info + .uni_dns_dom_name); } - if (r.info.dns_dom_info.hdr_forest_name.buffer) { - unistr2_to_ascii(forest_name, - &r.info.dns_dom_info.uni_forest_name, - sizeof(fstring) - 1); + if (forest_name && r.info.dns_dom_info.hdr_forest_name.buffer) { + *forest_name = unistr2_tdup(mem_ctx, + &r.info.dns_dom_info + .uni_forest_name); } - memcpy(domain_guid, &r.info.dns_dom_info.dom_guid,sizeof(struct uuid)); - - if (r.info.dns_dom_info.ptr_dom_sid != 0) { - *domain_sid = r.info.dns_dom_info.dom_sid.sid; + if (domain_guid) { + *domain_guid = talloc(mem_ctx, sizeof(**domain_guid)); + memcpy(*domain_guid, + &r.info.dns_dom_info.dom_guid, + sizeof(struct uuid)); + } + + if (domain_sid && r.info.dns_dom_info.ptr_dom_sid != 0) { + *domain_sid = talloc(mem_ctx, sizeof(**domain_sid)); + if (*domain_sid) { + sid_copy(*domain_sid, + &r.info.dns_dom_info.dom_sid.sid); + } } done: diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index b9974cba8a..7edd34c8dd 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -2834,11 +2834,17 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, DOM_SID *sid) DEBUG(5, ("Changing trust account or non-unix-user password, not updating /etc/passwd\n")); } else { /* update the UNIX password */ - if (lp_unix_password_sync() ) - if(!chgpasswd(pdb_get_username(pwd), "", plaintext_buf, True)) { + if (lp_unix_password_sync() ) { + struct passwd *passwd = Get_Pwnam(pdb_get_username(pwd)); + if (!passwd) { + DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); + } + + if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { pdb_free_sam(&pwd); return False; } + } } ZERO_STRUCT(plaintext_buf); @@ -2899,7 +2905,12 @@ static BOOL set_user_info_pw(char *pass, DOM_SID *sid) } else { /* update the UNIX password */ if (lp_unix_password_sync()) { - if(!chgpasswd(pdb_get_username(pwd), "", plaintext_buf, True)) { + struct passwd *passwd = Get_Pwnam(pdb_get_username(pwd)); + if (!passwd) { + DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); + } + + if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { pdb_free_sam(&pwd); return False; } diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c index 217e6b1d68..d9afde465d 100644 --- a/source3/rpcclient/cmd_lsarpc.c +++ b/source3/rpcclient/cmd_lsarpc.c @@ -68,9 +68,13 @@ static NTSTATUS cmd_lsa_query_info_policy(struct cli_state *cli, { POLICY_HND pol; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - DOM_SID dom_sid; - struct uuid dom_guid; - fstring sid_str, domain_name="", dns_name="", forest_name=""; + DOM_SID *dom_sid; + struct uuid *dom_guid; + fstring sid_str; + char *domain_name = NULL; + char *dns_name = NULL; + char *forest_name = NULL; + uint32 info_class = 3; if (argc > 2) { @@ -91,8 +95,8 @@ static NTSTATUS cmd_lsa_query_info_policy(struct cli_state *cli, if (!NT_STATUS_IS_OK(result)) goto done; result = cli_lsa_query_info_policy2(cli, mem_ctx, &pol, - info_class, domain_name, - dns_name, forest_name, + info_class, &domain_name, + &dns_name, &forest_name, &dom_guid, &dom_sid); break; default: @@ -103,28 +107,28 @@ static NTSTATUS cmd_lsa_query_info_policy(struct cli_state *cli, if (!NT_STATUS_IS_OK(result)) goto done; result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, - info_class, domain_name, + info_class, &domain_name, &dom_sid); } if (!NT_STATUS_IS_OK(result)) goto done; + + sid_to_string(sid_str, dom_sid); - sid_to_string(sid_str, &dom_sid); - - if (domain_name[0]) + if (domain_name) printf("domain %s has sid %s\n", domain_name, sid_str); else printf("could not query info for level %d\n", info_class); - if (dns_name[0]) + if (dns_name) printf("domain dns name is %s\n", dns_name); - if (forest_name[0]) + if (forest_name) printf("forest name is %s\n", forest_name); if (info_class == 12) { - printf("domain GUID is %s\n", - smb_uuid_string_static(dom_guid)); + printf("domain GUID is "); + smb_uuid_string_static(*dom_guid); } done: return result; diff --git a/source3/rpcclient/cmd_spoolss.c b/source3/rpcclient/cmd_spoolss.c index 798949fae9..f5a440c024 100644 --- a/source3/rpcclient/cmd_spoolss.c +++ b/source3/rpcclient/cmd_spoolss.c @@ -1336,7 +1336,7 @@ static WERROR cmd_spoolss_addprinterex(struct cli_state *cli, slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); strupper_m(servername); - /* Fill in the DRIVER_INFO_3 struct */ + /* Fill in the DRIVER_INFO_2 struct */ ZERO_STRUCT(info2); #if 0 /* JERRY */ init_unistr( &info2.servername, servername); diff --git a/source3/script/installswat.sh b/source3/script/installswat.sh index 027ca35110..c0285bda55 100755 --- a/source3/script/installswat.sh +++ b/source3/script/installswat.sh @@ -71,7 +71,7 @@ for ln in $LANGS; do done -# Install html documentation +# Install html documentation (if html documentation tree is here) if [ -d $SRCDIR../docs/htmldocs/ ]; then diff --git a/source3/script/mkbuildoptions.awk b/source3/script/mkbuildoptions.awk index cdc5bd9881..9c22662310 100644 --- a/source3/script/mkbuildoptions.awk +++ b/source3/script/mkbuildoptions.awk @@ -242,14 +242,14 @@ END { # add code to display the various type sizes print " /* Output the sizes of the various types */"; print " output(screen, \"\\nType sizes:\\n\");"; - print " output(screen, \" sizeof(char): %u\\n\",sizeof(char));"; - print " output(screen, \" sizeof(int): %u\\n\",sizeof(int));"; - print " output(screen, \" sizeof(long): %u\\n\",sizeof(long));"; - print " output(screen, \" sizeof(uint8): %u\\n\",sizeof(uint8));"; - print " output(screen, \" sizeof(uint16): %u\\n\",sizeof(uint16));"; - print " output(screen, \" sizeof(uint32): %u\\n\",sizeof(uint32));"; - print " output(screen, \" sizeof(short): %u\\n\",sizeof(short));"; - print " output(screen, \" sizeof(void*): %u\\n\",sizeof(void*));"; + print " output(screen, \" sizeof(char): %lu\\n\",(unsigned long)sizeof(char));"; + print " output(screen, \" sizeof(int): %lu\\n\",(unsigned long)sizeof(int));"; + print " output(screen, \" sizeof(long): %lu\\n\",(unsigned long)sizeof(long));"; + print " output(screen, \" sizeof(uint8): %lu\\n\",(unsigned long)sizeof(uint8));"; + print " output(screen, \" sizeof(uint16): %lu\\n\",(unsigned long)sizeof(uint16));"; + print " output(screen, \" sizeof(uint32): %lu\\n\",(unsigned long)sizeof(uint32));"; + print " output(screen, \" sizeof(short): %lu\\n\",(unsigned long)sizeof(short));"; + print " output(screen, \" sizeof(void*): %lu\\n\",(unsigned long)sizeof(void*));"; ################################################## # add code to give information about modules diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index e6117245e7..692e82680d 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -49,6 +49,16 @@ #include "includes.h" +#ifdef HAVE_WORKING_CRACKLIB +#include + +#ifndef HAVE_CRACKLIB_DICTPATH +#ifndef CRACKLIB_DICTPATH +#define CRACKLIB_DICTPATH SAMBA_CRACKLIB_DICTPATH +#endif +#endif +#endif + extern struct passdb_ops pdb_ops; static NTSTATUS check_oem_password(const char *user, @@ -441,25 +451,14 @@ while we were waiting\n", WTERMSIG(wstat))); return (chstat); } -BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root) +BOOL chgpasswd(const char *name, const struct passwd *pass, + const char *oldpass, const char *newpass, BOOL as_root) { pstring passwordprogram; pstring chatsequence; size_t i; size_t len; - struct passwd *pass; - - if (!name) { - DEBUG(1, ("chgpasswd: NULL username specfied !\n")); - } - - pass = Get_Pwnam(name); - if (!pass) { - DEBUG(1, ("chgpasswd: Username does not exist in system !\n")); - return False; - } - if (!oldpass) { oldpass = ""; } @@ -471,13 +470,6 @@ BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL #endif /* Take the passed information and test it for minimum criteria */ - /* Minimum password length */ - if (strlen(newpass) < lp_min_passwd_length()) { - /* too short, must be at least MINPASSWDLENGTH */ - DEBUG(0, ("chgpasswd: Password Change: user %s, New password is shorter than minimum password length = %d\n", - name, lp_min_passwd_length())); - return (False); /* inform the user */ - } /* Password is same as old password */ if (strcmp(oldpass, newpass) == 0) { @@ -570,7 +562,8 @@ the string %%u, and the given string %s does not.\n", passwordprogram )); #else /* ALLOW_CHANGE_PASSWORD */ -BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root) +BOOL chgpasswd(const char *name, const struct passwd *pass, + const char *oldpass, const char *newpass, BOOL as_root) { DEBUG(0, ("chgpasswd: Password changing not compiled in (user=%s)\n", name)); return (False); @@ -909,6 +902,8 @@ static NTSTATUS check_oem_password(const char *user, NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root) { + struct passwd *pass; + BOOL ret; uint32 min_len; @@ -936,7 +931,47 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw /* return NT_STATUS_PWD_TOO_SHORT; */ } - /* TODO: Add cracklib support here */ + pass = Get_Pwnam(pdb_get_username(hnd)); + if (!pass) { + DEBUG(1, ("check_oem_password: Username does not exist in system !?!\n")); + } + +#ifdef HAVE_WORKING_CRACKLIB + if (pass) { + /* if we can, become the user to overcome internal cracklib sillyness */ + if (!push_sec_ctx()) + return NT_STATUS_UNSUCCESSFUL; + + set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL); + set_re_uid(); + } + + if (lp_use_cracklib()) { + const char *crack_check_reason; + DEBUG(4, ("change_oem_password: Checking password for user [%s]" + " against cracklib. \n", pdb_get_username(hnd))); + DEBUGADD(4, ("If this is your last message, then something is " + "wrong with cracklib, it might be missing it's " + "dictionaries at %s\n", + CRACKLIB_DICTPATH)); + dbgflush(); + + crack_check_reason = FascistCheck(new_passwd, (char *)CRACKLIB_DICTPATH); + if (crack_check_reason) { + DEBUG(1, ("Password Change: user [%s], " + "New password failed cracklib test - %s\n", + pdb_get_username(hnd), crack_check_reason)); + + /* get back to where we should be */ + if (pass) + pop_sec_ctx(); + return NT_STATUS_PASSWORD_RESTRICTION; + } + } + + if (pass) + pop_sec_ctx(); +#endif /* * If unix password sync was requested, attempt to change @@ -951,7 +986,7 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw */ if(lp_unix_password_sync() && - !chgpasswd(pdb_get_username(hnd), old_passwd, new_passwd, as_root)) { + !chgpasswd(pdb_get_username(hnd), pass, old_passwd, new_passwd, as_root)) { return NT_STATUS_ACCESS_DENIED; } diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c index 46f688a219..19f225e973 100644 --- a/source3/smbd/quotas.c +++ b/source3/smbd/quotas.c @@ -50,33 +50,16 @@ BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_B #ifdef LINUX #include -#include +#include /* * This shouldn't be neccessary - it should be /usr/include/sys/quota.h - * Unfortunately, RH7.1 ships with a different quota system using struct mem_dqblk - * rather than the struct dqblk defined in /usr/include/sys/quota.h. - * This means we must include linux/quota.h to have a hope of working on - * RH7.1 systems. And it also means this breaks if the kernel is upgraded - * to a Linus 2.4.x (where x > the minor number shipped with RH7.1) until - * Linus synchronises with the AC patches. Sometimes I *hate* Linux :-). JRA. + * So we include all the files has *should* be in the system into a large, + * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA. */ -#include -#ifdef HAVE_LINUX_XQM_H -#include -#else -#ifdef HAVE_XFS_XQM_H -#include -#define HAVE_LINUX_XQM_H -#endif -#endif - -#include -#include - - -#define LINUX_QUOTAS_2 +#include "samba_linux_quota.h" +#include "samba_xfs_quota.h" typedef struct _LINUX_SMB_DISK_QUOTA { SMB_BIG_UINT bsize; @@ -92,22 +75,20 @@ typedef struct _LINUX_SMB_DISK_QUOTA { Abstract out the XFS Quota Manager quota get call. ****************************************************************************/ -static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp) +static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) { - int ret = -1; -#ifdef HAVE_LINUX_XQM_H struct fs_disk_quota D; + int ret; ZERO_STRUCT(D); - ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); + ret = quotactl(QCMD(Q_XGETQUOTA,XFS_USER_QUOTA), path, euser_id, (caddr_t)&D); - /* As XFS has group quotas, if getting the user quota fails, try getting the group instead. */ - if (ret) { - ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, getegid(), (caddr_t)&D); - if (ret) - return ret; - } + if (ret) + ret = quotactl(QCMD(Q_XGETQUOTA,XFS_GROUP_QUOTA), path, egrp_id, (caddr_t)&D); + + if (ret) + return ret; dp->bsize = (SMB_BIG_UINT)512; dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit; @@ -116,7 +97,7 @@ static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QU dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit; dp->curinodes = (SMB_BIG_UINT)D.d_icount; dp->curblocks = (SMB_BIG_UINT)D.d_bcount; -#endif + return ret; } @@ -124,48 +105,90 @@ static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QU Abstract out the old and new Linux quota get calls. ****************************************************************************/ -static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp) +static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) { - int ret = 0; -#ifdef LINUX_QUOTAS_1 - struct dqblk D; + struct v1_kern_dqblk D; + int ret; + ZERO_STRUCT(D); - dp->bsize = (SMB_BIG_UINT)1024; -#else /* LINUX_QUOTAS_2 */ - struct mem_dqblk D; + + ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); + + if (ret && errno != EDQUOT) + ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); + + if (ret && errno != EDQUOT) + return ret; + + dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; + dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; + dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; + dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; + dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; + dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; + dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks; + + return ret; +} + +static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) +{ + struct v2_kern_dqblk D; + int ret; + ZERO_STRUCT(D); -#ifndef QUOTABLOCK_SIZE -#define QUOTABLOCK_SIZE 1024 -#endif + + ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); + + if (ret && errno != EDQUOT) + ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); + + if (ret && errno != EDQUOT) + return ret; + dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; -#endif + dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; + dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; + dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; + dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; + dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; + dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize; + + return ret; +} + +/**************************************************************************** + Brand-new generic quota interface. +****************************************************************************/ + +static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) +{ + struct if_dqblk D; + int ret; + + ZERO_STRUCT(D); ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - /* Linux can have group quotas, if getting the user quota fails, try getting the group instead. */ - if (ret) { - ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, getegid(), (caddr_t)&D); - if (ret) - return ret; - } + if (ret && errno != EDQUOT) + ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); + if (ret && errno != EDQUOT) + return ret; + + dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; - -#ifdef LINUX_QUOTAS_1 - dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks; -#else /* LINUX_QUOTAS_2 */ - dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace)/ dp->bsize; -#endif + dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize; return ret; } /**************************************************************************** -try to get the disk space from disk quotas (LINUX version) + Try to get the disk space from disk quotas (LINUX version). ****************************************************************************/ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) @@ -178,9 +201,11 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB SMB_DEV_T devno; int found; uid_t euser_id; + gid_t egrp_id; euser_id = geteuid(); - + egrp_id = getegid(); + /* find the block device file */ if ( sys_stat(path, &S) == -1 ) @@ -208,10 +233,18 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB save_re_uid(); set_effective_uid(0); - if (strcmp(mnt->mnt_type, "xfs") == 0) - r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D); - else - r=get_smb_linux_vfs_quota(mnt->mnt_fsname, euser_id, &D); + + if (strcmp(mnt->mnt_type, "xfs")==0) { + r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); + } else { + r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); + if (r == -1 && errno != EDQUOT) { + r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); + if (r == -1 && errno != EDQUOT) + r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); + } + } + restore_re_uid(); /* Use softlimit to determine disk space, except when it has been exceeded */ @@ -920,8 +953,8 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0)) #else if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) -#endif /* ifdef HPUX */ return (False); +#endif /* ifdef HPUX */ #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) */ diff --git a/source3/tdb/tdb.c b/source3/tdb/tdb.c index c98b0936ed..ff70750385 100644 --- a/source3/tdb/tdb.c +++ b/source3/tdb/tdb.c @@ -853,6 +853,8 @@ static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length, tdb_off rec_ptr, last_ptr, newrec_ptr; struct list_struct newrec; + memset(&newrec, '\0', sizeof(newrec)); + if (tdb_lock(tdb, -1, F_WRLCK) == -1) return 0; diff --git a/source3/tests/crack.c b/source3/tests/crack.c new file mode 100644 index 0000000000..1342887852 --- /dev/null +++ b/source3/tests/crack.c @@ -0,0 +1,5 @@ + +int main(int argc, char **argv) { + FascistCheck("Foo", CRACKLIB_DICTPATH); + return 0; +} diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index b28365274c..9f0f64edec 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -48,27 +48,14 @@ typedef NTSTATUS (*rpc_command_fn)(const DOM_SID *, struct cli_state *, TALLOC_C * @return The Domain SID of the remote machine. **/ -static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli) +static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx) { DOM_SID *domain_sid; POLICY_HND pol; NTSTATUS result = NT_STATUS_OK; uint32 info_class = 5; - fstring domain_name; - TALLOC_CTX *mem_ctx; + char *domain_name; - if (!(domain_sid = malloc(sizeof(DOM_SID)))){ - DEBUG(0,("net_get_remote_domain_sid: malloc returned NULL!\n")); - goto error; - } - - if (!(mem_ctx=talloc_init("net_get_remote_domain_sid"))) - { - DEBUG(0,("net_get_remote_domain_sid: talloc_init returned NULL!\n")); - goto error; - } - - if (!cli_nt_session_open (cli, PI_LSARPC)) { fprintf(stderr, "could not initialise lsa pipe\n"); goto error; @@ -82,7 +69,7 @@ static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli) } result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class, - domain_name, domain_sid); + &domain_name, &domain_sid); if (!NT_STATUS_IS_OK(result)) { error: fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain); @@ -96,7 +83,6 @@ static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli) cli_lsa_close(cli, mem_ctx, &pol); cli_nt_session_close(cli); - talloc_destroy(mem_ctx); return domain_sid; } @@ -132,7 +118,7 @@ static int run_rpc_command(struct cli_state *cli_arg, const int pipe_idx, int co return -1; } - domain_sid = net_get_remote_domain_sid(cli); + domain_sid = net_get_remote_domain_sid(cli, mem_ctx); /* Create mem_ctx */ @@ -1928,10 +1914,11 @@ static int rpc_trustdom_establish(int argc, const char **argv) POLICY_HND connect_hnd; TALLOC_CTX *mem_ctx; NTSTATUS nt_status; - DOM_SID domain_sid; + DOM_SID *domain_sid; WKS_INFO_100 wks_info; char* domain_name; + char* domain_name_pol; char* acct_name; fstring pdc_name; @@ -2052,7 +2039,7 @@ static int rpc_trustdom_establish(int argc, const char **argv) /* Querying info level 5 */ nt_status = cli_lsa_query_info_policy(cli, mem_ctx, &connect_hnd, - 5 /* info level */, domain_name, + 5 /* info level */, &domain_name_pol, &domain_sid); if (NT_STATUS_IS_ERR(nt_status)) { DEBUG(0, ("LSA Query Info failed. Returned error was %s\n", @@ -2072,7 +2059,7 @@ static int rpc_trustdom_establish(int argc, const char **argv) if (!secrets_store_trusted_domain_password(domain_name, wks_info.uni_lan_grp.buffer, wks_info.uni_lan_grp.uni_str_len, opt_password, - domain_sid)) { + *domain_sid)) { DEBUG(0, ("Storing password for trusted domain failed.\n")); return -1; } @@ -2163,7 +2150,7 @@ static int rpc_trustdom_list(int argc, const char **argv) struct cli_state *cli, *remote_cli; NTSTATUS nt_status; const char *domain_name = NULL; - DOM_SID queried_dom_sid; + DOM_SID *queried_dom_sid; fstring ascii_sid, padding; int ascii_dom_name_len; POLICY_HND connect_hnd; @@ -2173,7 +2160,8 @@ static int rpc_trustdom_list(int argc, const char **argv) int i, pad_len, col_len = 20; DOM_SID *domain_sids; char **trusted_dom_names; - fstring pdc_name, dummy; + fstring pdc_name; + char *dummy; /* trusting domains listing variables */ POLICY_HND domain_hnd; @@ -2222,7 +2210,7 @@ static int rpc_trustdom_list(int argc, const char **argv) /* query info level 5 to obtain sid of a domain being queried */ nt_status = cli_lsa_query_info_policy( cli, mem_ctx, &connect_hnd, 5 /* info level */, - dummy, &queried_dom_sid); + &dummy, &queried_dom_sid); if (NT_STATUS_IS_ERR(nt_status)) { DEBUG(0, ("LSA Query Info failed. Returned error was %s\n", @@ -2304,8 +2292,8 @@ static int rpc_trustdom_list(int argc, const char **argv) /* SamrOpenDomain - we have to open domain policy handle in order to be able to enumerate accounts*/ nt_status = cli_samr_open_domain(cli, mem_ctx, &connect_hnd, - SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, - &queried_dom_sid, &domain_hnd); + SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, + queried_dom_sid, &domain_hnd); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("Couldn't open domain object. Error was %s\n", nt_errstr(nt_status))); diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 96e52964b4..74918045ee 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1072,6 +1072,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) DATA_BLOB session_key_krb5; SPNEGO_DATA reply; char *reply_base64; + int retval; const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL}; ssize_t len; @@ -1093,9 +1094,9 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) spnego.negTokenInit.mechListMIC.length); principal[spnego.negTokenInit.mechListMIC.length] = '\0'; - tkt = cli_krb5_get_ticket(principal, 0, &session_key_krb5); + retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5); - if (tkt.data == NULL) { + if (retval) { pstring user; @@ -1110,13 +1111,17 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) pstr_sprintf(user, "%s@%s", opt_username, opt_domain); - if (kerberos_kinit_password(user, opt_password, 0) != 0) { - DEBUG(10, ("Requesting TGT failed\n")); + if ((retval = kerberos_kinit_password(user, opt_password, 0))) { + DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval))); x_fprintf(x_stdout, "NA\n"); return True; } - tkt = cli_krb5_get_ticket(principal, 0, &session_key_krb5); + retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5); + + if (retval) { + DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval))); + } } data_blob_free(&session_key_krb5); diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index eae1f97b58..8a27684a4d 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -717,7 +717,7 @@ int main(int argc, const char **argv) argc -= 2; break; case 's': /* --configfile */ - pstrcpy(dyn_CONFIGFILE, optarg); + pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc)); argc -= 2; break; default: diff --git a/source3/utils/smbget.c b/source3/utils/smbget.c new file mode 100644 index 0000000000..92a3831752 --- /dev/null +++ b/source3/utils/smbget.c @@ -0,0 +1,574 @@ +/* + smbget: a wget-like utility with support for recursive downloading and + smb:// urls + Copyright (C) 2003-2004 Jelmer Vernooij + + 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 "libsmbclient.h" + +#if _FILE_OFFSET_BITS==64 +#define OFF_T_FORMAT "%lld" +#else +#define OFF_T_FORMAT "%ld" +#endif + +int columns = 0; + +time_t total_start_time = 0; +off_t total_bytes = 0; + +#define SMB_MAXPATHLEN MAXPATHLEN + +/* Number of bytes to read when checking whether local and remote file are really the same file */ +#define RESUME_CHECK_SIZE 512 +#define RESUME_DOWNLOAD_OFFSET 1024 +#define RESUME_CHECK_OFFSET RESUME_DOWNLOAD_OFFSET+RESUME_CHECK_SIZE +/* Number of bytes to read at once */ +#define SMB_DEFAULT_BLOCKSIZE 64000 + +const char *username = NULL, *password = NULL, *workgroup = NULL; +int nonprompt = 0, quiet = 0, dots = 0, keep_permissions = 0, verbose = 0; +int blocksize = SMB_DEFAULT_BLOCKSIZE; + +int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile); + +int get_num_cols(void) +{ +#ifdef TIOCGWINSZ + struct winsize ws; + if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) { + perror("ioctl"); + return 0; + } + return ws.ws_col; +#else +#warning No support for TIOCGWINSZ + char *cols = getenv("COLUMNS"); + if(!cols) return 0; + return atoi(cols); +#endif +} + +void change_columns(int sig) +{ + columns = get_num_cols(); +} + +void human_readable(off_t s, char *buffer, int l) +{ + if(s > 1024 * 1024 * 1024) snprintf(buffer, l, "%.2fGb", 1.0 * s / (1024 * 1024 * 1024)); + else if(s > 1024 * 1024) snprintf(buffer, l, "%.2fMb", 1.0 * s / (1024 * 1024)); + else if(s > 1024) snprintf(buffer, l, "%.2fkb", 1.0 * s / 1024); + else snprintf(buffer, l, OFF_T_FORMAT"b", s); +} + +void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *un, int unlen, char *pw, int pwlen) +{ + static char hasasked = 0; + char *wgtmp, *usertmp; + char tmp[128]; + + if(hasasked) return; + hasasked = 1; + + if(!nonprompt && !username) { + printf("Username for %s at %s [guest] ", shr, srv); + fgets(tmp, sizeof(tmp), stdin); + if(tmp[strlen(tmp)-1] == '\n')tmp[strlen(tmp)-1] = '\0'; + strncpy(un, tmp, unlen-1); + } else if(username) strncpy(un, username, unlen-1); + + if(!nonprompt && !password) { + char *prompt, *pass; + asprintf(&prompt, "Password for %s at %s: ", shr, srv); + pass = getpass(prompt); + free(prompt); + strncpy(pw, pass, pwlen-1); + } else if(password) strncpy(pw, password, pwlen-1); + + if(workgroup)strncpy(wg, workgroup, wglen-1); + + wgtmp = strndup(wg, wglen); + usertmp = strndup(un, unlen); + if(!quiet)printf("Using workgroup %s, %s%s\n", wgtmp, *usertmp?"user ":"guest user", usertmp); + free(wgtmp); free(usertmp); +} + +int smb_download_dir(const char *base, const char *name, int resume) +{ + char path[SMB_MAXPATHLEN]; + int dirhandle; + struct smbc_dirent *dirent; + const char *relname = name; + char *tmpname; + struct stat remotestat; + snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (base[0] && name[0] && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name); + + /* List files in directory and call smb_download_file on them */ + dirhandle = smbc_opendir(path); + if(dirhandle < 1) { + if(errno == ENOTDIR) return smb_download_file(base, name, 1, resume, NULL); + fprintf(stderr, "Can't open directory %s: %s\n", path, strerror(errno)); + return 0; + } + + while(*relname == '/')relname++; + mkdir(relname, 0755); + + tmpname = strdup(name); + + while((dirent = smbc_readdir(dirhandle))) { + char *newname; + if(!strcmp(dirent->name, ".") || !strcmp(dirent->name, ".."))continue; + asprintf(&newname, "%s/%s", tmpname, dirent->name); + switch(dirent->smbc_type) { + case SMBC_DIR: + smb_download_dir(base, newname, resume); + break; + + case SMBC_WORKGROUP: + smb_download_dir("smb://", dirent->name, resume); + break; + + case SMBC_SERVER: + smb_download_dir("smb://", dirent->name, resume); + break; + + case SMBC_FILE: + smb_download_file(base, newname, 1, resume, NULL); + break; + + case SMBC_FILE_SHARE: + smb_download_dir(base, newname, resume); + break; + + case SMBC_PRINTER_SHARE: + if(!quiet)printf("Ignoring printer share %s\n", dirent->name); + break; + + case SMBC_COMMS_SHARE: + if(!quiet)printf("Ignoring comms share %s\n", dirent->name); + break; + + case SMBC_IPC_SHARE: + if(!quiet)printf("Ignoring ipc$ share %s\n", dirent->name); + break; + + default: + fprintf(stderr, "Ignoring file '%s' of type '%d'\n", newname, dirent->smbc_type); + break; + } + free(newname); + } + free(tmpname); + + if(keep_permissions) { + if(smbc_fstat(dirhandle, &remotestat) < 0) { + fprintf(stderr, "Unable to get stats on %s on remote server\n", path); + smbc_closedir(dirhandle); + return 0; + } + + if(chmod(relname, remotestat.st_mode) < 0) { + fprintf(stderr, "Unable to change mode of local dir %s to %o\n", relname, remotestat.st_mode); + smbc_closedir(dirhandle); + return 0; + } + } + + smbc_closedir(dirhandle); + return 1; +} + +char *print_time(long t) +{ + static char buffer[100]; + int secs, mins, hours; + if(t < -1) { + strncpy(buffer, "Unknown", sizeof(buffer)); + return buffer; + } + + secs = (int)t % 60; + mins = (int)t / 60 % 60; + hours = (int)t / (60 * 60); + snprintf(buffer, sizeof(buffer)-1, "%02d:%02d:%02d", hours, mins, secs); + return buffer; +} + +void print_progress(const char *name, time_t start, time_t now, off_t start_pos, off_t pos, off_t total) +{ + double avg = 0.0; + long eta = -1; + double prcnt = 0.0; + char hpos[20], htotal[20], havg[20]; + char *status, *filename; + int len; + if(now - start)avg = 1.0 * (pos - start_pos) / (now - start); + eta = (total - pos - start_pos) / avg; + if(total)prcnt = 100.0 * pos / total; + + human_readable(pos, hpos, sizeof(hpos)); + human_readable(total, htotal, sizeof(htotal)); + human_readable(avg, havg, sizeof(havg)); + + len = asprintf(&status, "%s of %s (%.2f%%) at %s/s ETA: %s", hpos, htotal, prcnt, havg, print_time(eta)); + + if(columns) { + int required = strlen(name), available = columns - len - strlen("[] "); + if(required > available) asprintf(&filename, "...%s", name + required - available + 3); + else filename = strndup(name, available); + } else filename = strdup(name); + + fprintf(stderr, "\r[%s] %s", filename, status); + + free(filename); free(status); +} + +int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile) { + int remotehandle, localhandle; + time_t start_time = time(NULL); + const char *newpath; + char path[SMB_MAXPATHLEN]; + char checkbuf[2][RESUME_CHECK_SIZE]; + char *readbuf = NULL; + off_t offset_download = 0, offset_check = 0, curpos = 0, start_offset = 0; + struct stat localstat, remotestat; + + snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (*base && *name && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name); + + remotehandle = smbc_open(path, O_RDONLY, 0755); + + if(remotehandle < 0) { + switch(errno) { + case EISDIR: + if(!recursive) { + fprintf(stderr, "%s is a directory. Specify -R to download recursively\n", path); + return 0; + } + smb_download_dir(base, name, resume); + return 0; + + case ENOENT: + fprintf(stderr, "%s can't be found on the remote server\n", path); + return 0; + + case ENOMEM: + fprintf(stderr, "Not enough memory\n"); + exit(1); + return 0; + + case ENODEV: + fprintf(stderr, "The share name used in %s does not exist\n", path); + return 0; + + case EACCES: + fprintf(stderr, "You don't have enough permissions to access %s\n", path); + return 0; + + default: + perror("smbc_open"); + return 0; + } + } + + if(smbc_fstat(remotehandle, &remotestat) < 0) { + fprintf(stderr, "Can't stat %s: %s\n", path, strerror(errno)); + return 0; + } + + if(outfile) newpath = outfile; + else if(!name[0]) { + newpath = strrchr(base, '/'); + if(newpath)newpath++; else newpath = base; + } else newpath = name; + + if(newpath[0] == '/')newpath++; + + /* Open local file and, if necessary, resume */ + localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | (!resume?O_EXCL:0), 0755); + if(localhandle < 0) { + fprintf(stderr, "Can't open %s: %s\n", newpath, strerror(errno)); + smbc_close(remotehandle); + return 0; + } + + fstat(localhandle, &localstat); + + start_offset = localstat.st_size; + + if(localstat.st_size && localstat.st_size == remotestat.st_size) { + if(verbose)fprintf(stderr, "%s is already downloaded completely.\n", path); + else if(!quiet)fprintf(stderr, "%s\n", path); + smbc_close(remotehandle); + close(localhandle); + return 1; + } + + if(localstat.st_size > RESUME_CHECK_OFFSET && remotestat.st_size > RESUME_CHECK_OFFSET) { + offset_download = localstat.st_size - RESUME_DOWNLOAD_OFFSET; + offset_check = localstat.st_size - RESUME_CHECK_OFFSET; + if(verbose)printf("Trying to start resume of %s at "OFF_T_FORMAT"\n" + "At the moment "OFF_T_FORMAT" of "OFF_T_FORMAT" bytes have been retrieved\n", newpath, offset_check, + localstat.st_size, remotestat.st_size); + } + + if(offset_check) { + off_t off1, off2; + /* First, check all bytes from offset_check to offset_download */ + off1 = lseek(localhandle, offset_check, SEEK_SET); + if(off1 < 0) { + fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in local file %s\n", offset_check, newpath); + smbc_close(remotehandle); close(localhandle); + return 0; + } + + off2 = smbc_lseek(remotehandle, offset_check, SEEK_SET); + if(off2 < 0) { + fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in remote file %s\n", offset_check, newpath); + smbc_close(remotehandle); close(localhandle); + return 0; + } + + if(off1 != off2) { + fprintf(stderr, "Offset in local and remote files is different (local: "OFF_T_FORMAT", remote: "OFF_T_FORMAT")\n", off1, off2); + return 0; + } + + if(smbc_read(remotehandle, checkbuf[0], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) { + fprintf(stderr, "Can't read %d bytes from remote file %s\n", RESUME_CHECK_SIZE, path); + smbc_close(remotehandle); close(localhandle); + return 0; + } + + if(read(localhandle, checkbuf[1], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) { + fprintf(stderr, "Can't read %d bytes from local file %s\n", RESUME_CHECK_SIZE, name); + smbc_close(remotehandle); close(localhandle); + return 0; + } + + if(memcmp(checkbuf[0], checkbuf[1], RESUME_CHECK_SIZE) == 0) { + if(verbose)printf("Current local and remote file appear to be the same. Starting download from offset "OFF_T_FORMAT"\n", offset_download); + } else { + fprintf(stderr, "Local and remote file appear to be different, not doing resume for %s\n", path); + smbc_close(remotehandle); close(localhandle); + return 0; + } + } + + readbuf = malloc(blocksize); + + /* Now, download all bytes from offset_download to the end */ + for(curpos = offset_download; curpos < remotestat.st_size; curpos+=blocksize) { + ssize_t bytesread = smbc_read(remotehandle, readbuf, blocksize); + if(bytesread < 0) { + fprintf(stderr, "Can't read %d bytes at offset "OFF_T_FORMAT", file %s\n", blocksize, curpos, path); + smbc_close(remotehandle); close(localhandle); + free(readbuf); + return 0; + } + + total_bytes += bytesread; + + if(write(localhandle, readbuf, bytesread) < 0) { + fprintf(stderr, "Can't write %d bytes to local file %s at offset "OFF_T_FORMAT"\n", bytesread, path, curpos); + free(readbuf); + smbc_close(remotehandle); close(localhandle); + return 0; + } + + if(dots)fputc('.', stderr); + else if(!quiet) { + print_progress(newpath, start_time, time(NULL), start_offset, curpos, remotestat.st_size); + } + } + + free(readbuf); + + if(dots){ + fputc('\n', stderr); + printf("%s downloaded\n", path); + } else if(!quiet) { + int i; + fprintf(stderr, "\r%s", path); + if(columns) { + for(i = strlen(path); i < columns; i++) { + fputc(' ', stderr); + } + } + fputc('\n', stderr); + } + + if(keep_permissions) { + if(fchmod(localhandle, remotestat.st_mode) < 0) { + fprintf(stderr, "Unable to change mode of local file %s to %o\n", path, remotestat.st_mode); + smbc_close(remotehandle); + close(localhandle); + return 0; + } + } + smbc_close(remotehandle); + close(localhandle); + return 1; +} + +void clean_exit(void) +{ + char bs[100]; + human_readable(total_bytes, bs, sizeof(bs)); + if(!quiet)fprintf(stderr, "Downloaded %s in %lu seconds\n", bs, time(NULL) - total_start_time); + exit(0); +} + +void signal_quit(int v) +{ + clean_exit(); +} + +int readrcfile(const char *name, const struct poptOption long_options[]) +{ + FILE *fd = fopen(name, "r"); + int lineno = 0, i; + char var[101], val[101]; + char found; + int *intdata; char **stringdata; + if(!fd) { + fprintf(stderr, "Can't open RC file %s\n", name); + return 1; + } + + while(!feof(fd)) { + lineno++; + if(fscanf(fd, "%100s %100s\n", var, val) < 2) { + fprintf(stderr, "Can't parse line %d of %s, ignoring.\n", lineno, name); + continue; + } + + found = 0; + + for(i = 0; long_options[i].shortName; i++) { + if(!long_options[i].longName)continue; + if(strcmp(long_options[i].longName, var)) continue; + if(!long_options[i].arg)continue; + + switch(long_options[i].argInfo) { + case POPT_ARG_NONE: + intdata = (int *)long_options[i].arg; + if(!strcmp(val, "on")) *intdata = 1; + else if(!strcmp(val, "off")) *intdata = 0; + else fprintf(stderr, "Illegal value %s for %s at line %d in %s\n", val, var, lineno, name); + break; + case POPT_ARG_INT: + intdata = (int *)long_options[i].arg; + *intdata = atoi(val); + break; + case POPT_ARG_STRING: + stringdata = (char **)long_options[i].arg; + *stringdata = strdup(val); + break; + default: + fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name); + break; + } + + found = 1; + } + if(!found) { + fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name); + } + } + + fclose(fd); + return 0; +} + +int main(int argc, const char **argv) +{ + int resume = 0, recursive = 0; + int c = 0; + int debuglevel = 0; + const char *file = NULL; + char *rcfile = NULL; + char *outputfile = NULL; + struct poptOption long_options[] = { + {"guest", 'a', POPT_ARG_NONE, NULL, 'a', "Work as user guest" }, + {"resume", 'r', POPT_ARG_NONE, &resume, 0, "Automatically resume aborted files" }, + {"recursive", 'R', POPT_ARG_NONE, &recursive, 0, "Recursively download files" }, + {"username", 'u', POPT_ARG_STRING, &username, 'u', "Username to use" }, + {"password", 'p', POPT_ARG_STRING, &password, 'p', "Password to use" }, + {"workgroup", 'w', POPT_ARG_STRING, &workgroup, 'w', "Workgroup to use (optional)" }, + {"nonprompt", 'n', POPT_ARG_NONE, &nonprompt, 'n', "Don't ask anything (non-interactive)" }, + {"debuglevel", 'd', POPT_ARG_INT, &debuglevel, 'd', "Debuglevel to use" }, + {"outputfile", 'o', POPT_ARG_STRING, &outputfile, 'o', "Write downloaded data to specified file" }, + {"dots", 'D', POPT_ARG_NONE, &dots, 'D', "Show dots as progress indication" }, + {"quiet", 'q', POPT_ARG_NONE, &quiet, 'q', "Be quiet" }, + {"verbose", 'v', POPT_ARG_NONE, &verbose, 'v', "Be verbose" }, + {"keep-permissions", 'P', POPT_ARG_NONE, &keep_permissions, 'P', "Keep permissions" }, + {"blocksize", 'b', POPT_ARG_INT, &blocksize, 'b', "Change number of bytes in a block"}, + {"rcfile", 'f', POPT_ARG_STRING, NULL, 0, "Use specified rc file"}, + POPT_AUTOHELP + POPT_TABLEEND + }; + poptContext pc; + + /* only read rcfile if it exists */ + asprintf(&rcfile, "%s/.smbgetrc", getenv("HOME")); + if(access(rcfile, F_OK) == 0) readrcfile(rcfile, long_options); + free(rcfile); + +#ifdef SIGWINCH + signal(SIGWINCH, change_columns); +#endif + signal(SIGINT, signal_quit); + signal(SIGTERM, signal_quit); + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + + while((c = poptGetNextOpt(pc)) >= 0) { + switch(c) { + case 'f': + readrcfile(poptGetOptArg(pc), long_options); + break; + case 'a': + username = ""; password = ""; + break; + } + } + + if(outputfile && recursive) { + fprintf(stderr, "The -o and -R options can not be used together.\n"); + return 1; + } + + if(smbc_init(get_auth_data, debuglevel) < 0) { + fprintf(stderr, "Unable to initialize libsmbclient\n"); + return 1; + } + + columns = get_num_cols(); + + total_start_time = time(NULL); + + while((file = poptGetArg(pc))) { + if(!recursive) return smb_download_file(file, "", recursive, resume, outputfile); + else return smb_download_dir(file, "", resume); + } + + clean_exit(); + + return 0; +} -- cgit