diff options
author | Gerald Carter <jerry@samba.org> | 2007-03-20 16:56:16 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2007-03-20 16:56:16 +0000 |
commit | 651d5a89c59c107c05e789358624058e16af1b66 (patch) | |
tree | dfd29754255ea87b30eb16a06c505e42f98b9be3 /source | |
parent | 0f475ed1a387e37d477fd434c06ad5783c58adea (diff) | |
download | samba-651d5a89c59c107c05e789358624058e16af1b66.tar.gz samba-651d5a89c59c107c05e789358624058e16af1b66.tar.xz samba-651d5a89c59c107c05e789358624058e16af1b66.zip |
r21889: * Pull from SAMBA-3_0_25 svn r21888
* Set version to 3.0.25pre2
Diffstat (limited to 'source')
121 files changed, 5296 insertions, 2218 deletions
diff --git a/source/Makefile.in b/source/Makefile.in index 3f3aa5ea57a..f27fed1f391 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -159,7 +159,8 @@ TORTURE_PROGS = bin/smbtorture@EXEEXT@ bin/msgtest@EXEEXT@ \ bin/locktest2@EXEEXT@ bin/nsstest@EXEEXT@ bin/vfstest@EXEEXT@ \ bin/pdbtest@EXEEXT@ bin/talloctort@EXEEXT@ bin/replacetort@EXEEXT@ -BIN_PROGS = $(BIN_PROGS1) $(BIN_PROGS2) $(BIN_PROGS3) @EXTRA_BIN_PROGS@ +BIN_PROGS = $(BIN_PROGS1) $(BIN_PROGS2) $(BIN_PROGS3) @EXTRA_BIN_PROGS@ \ + @SMBMOUNT_PROGS@ EVERYTHING_PROGS = bin/debug2html@EXEEXT@ bin/smbfilter@EXEEXT@ \ bin/talloctort@EXEEXT@ bin/replacetort@EXEEXT@ \ @@ -788,6 +789,10 @@ WBINFO_OBJ = nsswitch/wbinfo.o $(LIBSAMBA_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ WINBIND_NSS_OBJ = $(WBCOMMON_OBJ) $(LIBREPLACE_OBJ) $(SOCKET_WRAPPER_OBJ) @WINBIND_NSS_EXTRA_OBJS@ +SMB_KRB5_LOCATOR_OBJ1 = libads/smb_krb5_locator.o +SMB_KRB5_LOCATOR_OBJ = $(SMB_KRB5_LOCATOR_OBJ1) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ + $(LIBNMB_OBJ) $(RPC_PARSE_OBJ1) $(SECRETS_OBJ) $(LIBSAMBA_OBJ) $(DOSERR_OBJ) + POPT_OBJ=popt/findme.o popt/popt.o popt/poptconfig.o \ popt/popthelp.o popt/poptparse.o @@ -1275,6 +1280,12 @@ bin/winbindd@EXEEXT@: $(WINBINDD_OBJ) @BUILD_POPT@ bin/.dummy $(LDAP_LIBS) $(KRB5LIBS) $(LIBS) \ @SONAMEFLAG@`basename $@`@NSSSONAMEVERSIONSUFFIX@ +@SMB_KRB5_LOCATOR@: $(SMB_KRB5_LOCATOR_OBJ) + @echo "Linking $@" + @$(SHLD) $(LDSHFLAGS) -o $@ $(SMB_KRB5_LOCATOR_OBJ) \ + $(LDAP_LIBS) $(LIBS) -lcom_err \ + @SONAMEFLAG@`basename $@` + bin/pam_winbind.@SHLIBEXT@: $(PAM_WINBIND_OBJ) bin/.dummy @echo "Linking shared library $@" @$(SHLD) $(LDSHFLAGS) -o $@ $(PAM_WINBIND_OBJ) -lpam @INIPARSERLIBS@ $(GPLIBS) \ @@ -1655,7 +1666,8 @@ revert: @$(SHELL) $(srcdir)/script/revert.sh $(BINDIR) $(BIN_PROGS) $(SCRIPTS) installman: installdirs - @$(SHELL) $(srcdir)/script/installman.sh $(DESTDIR)$(MANDIR) $(srcdir) C "@ROFF@" + @SMBMOUNT_PROGS="@SMBMOUNT_PROGS@" $(SHELL) \ + $(srcdir)/script/installman.sh $(DESTDIR)$(MANDIR) $(srcdir) C "@ROFF@" .PHONY: showlayout diff --git a/source/VERSION b/source/VERSION index fc1f872b07a..4d4416c8ee3 100644 --- a/source/VERSION +++ b/source/VERSION @@ -47,7 +47,7 @@ SAMBA_VERSION_REVISION= # e.g. SAMBA_VERSION_PRE_RELEASE=1 # # -> "2.2.9pre1" # ######################################################## -SAMBA_VERSION_PRE_RELEASE=1 +SAMBA_VERSION_PRE_RELEASE=2 ######################################################## # For 'rc' releases the version will be # diff --git a/source/auth/auth_domain.c b/source/auth/auth_domain.c index 6468c18cb0e..a32677d0370 100644 --- a/source/auth/auth_domain.c +++ b/source/auth/auth_domain.c @@ -237,7 +237,7 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx, user_info->logon_parameters,/* flags such as 'allow workstation logon' */ dc_name, /* server name */ user_info->smb_name, /* user name logging on. */ - user_info->domain, /* domain name */ + user_info->client_domain, /* domain name */ user_info->wksta_name, /* workstation name */ chal, /* 8 byte challenge. */ user_info->lm_resp, /* lanman 24 byte response */ diff --git a/source/auth/auth_winbind.c b/source/auth/auth_winbind.c index fa56757950d..f06f83f4065 100644 --- a/source/auth/auth_winbind.c +++ b/source/auth/auth_winbind.c @@ -108,7 +108,8 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, /* we are contacting the privileged pipe */ become_root(); - result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); + result = winbindd_priv_request_response(WINBINDD_PAM_AUTH_CRAP, + &request, &response); unbecome_root(); if ( result == NSS_STATUS_UNAVAIL ) { diff --git a/source/client/client.c b/source/client/client.c index 8ed3f1dc21e..e95b9ed9ce3 100644 --- a/source/client/client.c +++ b/source/client/client.c @@ -271,19 +271,17 @@ static int do_cd(char *newdir) pstrcpy(saved_dir, cur_dir); - if (*p == CLI_DIRSEP_CHAR) + if (*p == CLI_DIRSEP_CHAR) { pstrcpy(cur_dir,p); - else + } else { pstrcat(cur_dir,p); - - if ((cur_dir[0] != '\0') && (*(cur_dir+strlen(cur_dir)-1) != CLI_DIRSEP_CHAR)) { - pstrcat(cur_dir, CLI_DIRSEP_STR); + if ((cur_dir[0] != '\0') && (*(cur_dir+strlen(cur_dir)-1) != CLI_DIRSEP_CHAR)) { + pstrcat(cur_dir, CLI_DIRSEP_STR); + } } - dos_clean_name(cur_dir); + clean_name(cur_dir); pstrcpy( dname, cur_dir ); - pstrcat(cur_dir,CLI_DIRSEP_STR); - dos_clean_name(cur_dir); if ( !cli_resolve_path( "", cli, dname, &targetcli, targetpath ) ) { d_printf("cd %s: %s\n", dname, cli_errstr(cli)); @@ -291,9 +289,9 @@ static int do_cd(char *newdir) goto out; } - - if ( strequal(targetpath,CLI_DIRSEP_STR ) ) - return 0; + if (strequal(targetpath,CLI_DIRSEP_STR )) { + return 0; + } /* Use a trans2_qpathinfo to test directories for modern servers. Except Win9x doesn't support the qpathinfo_basic() call..... */ @@ -312,7 +310,7 @@ static int do_cd(char *newdir) } } else { pstrcat( targetpath, CLI_DIRSEP_STR ); - dos_clean_name( targetpath ); + clean_name( targetpath ); if ( !cli_chkpath(targetcli, targetpath) ) { d_printf("cd %s: %s\n", dname, cli_errstr(targetcli)); @@ -387,7 +385,7 @@ static void display_finfo(file_info *finfo) finfo->name, attrib_string(finfo->mode), (double)finfo->size, - time_to_asc(&t)); + time_to_asc(t)); dir_total += finfo->size; } else { pstring afname; @@ -398,25 +396,25 @@ static void display_finfo(file_info *finfo) return; /* create absolute filename for cli_nt_create() FIXME */ pstrcpy( afname, cwd); - pstrcat( afname, "\\"); + pstrcat( afname, CLI_DIRSEP_STR); pstrcat( afname, finfo->name); /* print file meta date header */ d_printf( "FILENAME:%s\n", afname); d_printf( "MODE:%s\n", attrib_string(finfo->mode)); d_printf( "SIZE:%.0f\n", (double)finfo->size); - d_printf( "MTIME:%s", time_to_asc(&t)); - fnum = cli_nt_create(cli, afname, CREATE_ACCESS_READ); + d_printf( "MTIME:%s", time_to_asc(t)); + fnum = cli_nt_create(finfo->cli, afname, CREATE_ACCESS_READ); if (fnum == -1) { DEBUG( 0, ("display_finfo() Failed to open %s: %s\n", afname, - cli_errstr( cli))); + cli_errstr( finfo->cli))); } else { SEC_DESC *sd = NULL; - sd = cli_query_secdesc(cli, fnum, ctx); + sd = cli_query_secdesc(finfo->cli, fnum, ctx); if (!sd) { DEBUG( 0, ("display_finfo() failed to " "get security descriptor: %s", - cli_errstr( cli))); + cli_errstr( finfo->cli))); } else { display_sec_desc(sd); } @@ -591,7 +589,8 @@ static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, return; p[1] = 0; pstrcat(mask2, f->name); - pstrcat(mask2,"\\*"); + pstrcat(mask2,CLI_DIRSEP_STR); + pstrcat(mask2,"*"); add_to_do_list_queue(mask2); } return; @@ -714,6 +713,11 @@ static int cmd_dir(void) pstrcat(mask,"*"); } + if (showacls) { + /* cwd is only used if showacls is on */ + pstrcpy(cwd, cur_dir); + } + do_list(mask, attribute, display_finfo, recurse, True); rc = do_dskattr(); @@ -790,17 +794,6 @@ static int do_get(char *rname, char *lname, BOOL reget) GetTimeOfDay(&tp_start); - if ( targetcli->dfsroot ) { - pstring path; - - /* we need to refer to the full \server\share\path format - for dfs shares */ - - pstrcpy( path, targetname ); - cli_dfs_make_full_path( targetname, targetcli->desthost, - targetcli->share, path); - } - fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE); if (fnum == -1) { @@ -924,7 +917,7 @@ static int cmd_get(void) return 1; } pstrcpy(lname,p); - dos_clean_name(rname); + clean_name(rname); next_token_nr(NULL,lname,NULL,sizeof(lname)); @@ -1025,7 +1018,7 @@ static int cmd_more(void) unlink(lname); return 1; } - dos_clean_name(rname); + clean_name(rname); rc = do_get(rname, lname, False); @@ -1155,14 +1148,20 @@ static int cmd_mkdir(void) if (recurse) { pstring ddir; pstring ddir2; + struct cli_state *targetcli; + pstring targetname; *ddir2 = 0; - pstrcpy(ddir,mask); + if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) { + return 1; + } + + pstrcpy(ddir,targetname); trim_char(ddir,'.','\0'); p = strtok(ddir,"/\\"); while (p) { pstrcat(ddir2,p); - if (!cli_chkpath(cli, ddir2)) { + if (!cli_chkpath(targetcli, ddir2)) { do_mkdir(ddir2); } pstrcat(ddir2,CLI_DIRSEP_STR); @@ -1358,7 +1357,7 @@ static int cmd_put(void) else pstrcat(rname,lname); - dos_clean_name(rname); + clean_name(rname); { SMB_STRUCT_STAT st; @@ -1672,13 +1671,13 @@ static void do_del(file_info *finfo) { pstring mask; - pstr_sprintf( mask, "%s\\%s", finfo->dir, finfo->name ); + pstr_sprintf( mask, "%s%c%s", finfo->dir, CLI_DIRSEP_CHAR, finfo->name ); if (finfo->mode & aDIR) return; - if (!cli_unlink(cli, mask)) { - d_printf("%s deleting remote file %s\n",cli_errstr(cli),mask); + if (!cli_unlink(finfo->cli, mask)) { + d_printf("%s deleting remote file %s\n",cli_errstr(finfo->cli),mask); } } @@ -1717,6 +1716,8 @@ static int cmd_wdel(void) pstring mask; pstring buf; uint16 attribute; + struct cli_state *targetcli; + pstring targetname; if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { d_printf("wdel 0x<attrib> <wcard>\n"); @@ -1733,13 +1734,17 @@ static int cmd_wdel(void) pstrcpy(mask,cur_dir); pstrcat(mask,buf); - if (!cli_unlink_full(cli, mask, attribute)) { - d_printf("%s deleting remote files %s\n",cli_errstr(cli),mask); + if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) { + d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli)); + return 1; + } + + if (!cli_unlink_full(targetcli, targetname, attribute)) { + d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname); } return 0; } - /**************************************************************************** ****************************************************************************/ @@ -1779,6 +1784,146 @@ static int cmd_open(void) return 0; } +/**************************************************************************** +****************************************************************************/ + +static int cmd_posix_open(void) +{ + pstring mask; + pstring buf; + struct cli_state *targetcli; + pstring targetname; + mode_t mode; + int fnum; + + pstrcpy(mask,cur_dir); + + if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { + d_printf("posix_open <filename> 0<mode>\n"); + return 1; + } + pstrcat(mask,buf); + if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { + d_printf("posix_open <filename> 0<mode>\n"); + return 1; + } + mode = (mode_t)strtol(buf, (char **)NULL, 8); + + if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) { + d_printf("posix_open %s: %s\n", mask, cli_errstr(cli)); + return 1; + } + + fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode); + if (fnum == -1) { + fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode); + if (fnum != -1) { + d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum); + } else { + d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli)); + } + } else { + d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum); + } + + return 0; +} + +static int cmd_posix_mkdir(void) +{ + pstring mask; + pstring buf; + struct cli_state *targetcli; + pstring targetname; + mode_t mode; + int fnum; + + pstrcpy(mask,cur_dir); + + if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { + d_printf("posix_mkdir <filename> 0<mode>\n"); + return 1; + } + pstrcat(mask,buf); + if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { + d_printf("posix_mkdir <filename> 0<mode>\n"); + return 1; + } + mode = (mode_t)strtol(buf, (char **)NULL, 8); + + if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) { + d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli)); + return 1; + } + + fnum = cli_posix_mkdir(targetcli, targetname, mode); + if (fnum == -1) { + d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli)); + } else { + d_printf("posix_mkdir created directory %s\n", targetname); + } + + return 0; +} + +static int cmd_posix_unlink(void) +{ + pstring mask; + pstring buf; + struct cli_state *targetcli; + pstring targetname; + + pstrcpy(mask,cur_dir); + + if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { + d_printf("posix_unlink <filename>\n"); + return 1; + } + pstrcat(mask,buf); + + if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) { + d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli)); + return 1; + } + + if (!cli_posix_unlink(targetcli, targetname)) { + d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli)); + } else { + d_printf("posix_unlink deleted file %s\n", targetname); + } + + return 0; +} + +static int cmd_posix_rmdir(void) +{ + pstring mask; + pstring buf; + struct cli_state *targetcli; + pstring targetname; + + pstrcpy(mask,cur_dir); + + if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) { + d_printf("posix_rmdir <filename>\n"); + return 1; + } + pstrcat(mask,buf); + + if (!cli_resolve_path( "", cli, mask, &targetcli, targetname)) { + d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli)); + return 1; + } + + if (!cli_posix_rmdir(targetcli, targetname)) { + d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli)); + } else { + d_printf("posix_rmdir deleted directory %s\n", targetname); + } + + return 0; +} + static int cmd_close(void) { fstring buf; @@ -1829,6 +1974,9 @@ static int cmd_posix(void) if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) { pstrcat(caps, "pathnames "); } + if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) { + pstrcat(caps, "posix_path_operations "); + } if (strlen(caps) > 0 && caps[strlen(caps)-1] == ' ') { caps[strlen(caps)-1] = '\0'; @@ -2013,6 +2161,8 @@ static int cmd_symlink(void) { pstring oldname,newname; pstring buf,buf2; + struct cli_state *targetcli; + pstring targetname; if (!SERVER_HAS_UNIX_CIFS(cli)) { d_printf("Server doesn't support UNIX CIFS calls.\n"); @@ -2030,9 +2180,14 @@ static int cmd_symlink(void) pstrcpy(oldname,buf); pstrcat(newname,buf2); - if (!cli_unix_symlink(cli, oldname, newname)) { + if ( !cli_resolve_path( "", cli, oldname, &targetcli, targetname ) ) { + d_printf("link %s: %s\n", oldname, cli_errstr(cli)); + return 1; + } + + if (!cli_unix_symlink(targetcli, targetname, newname)) { d_printf("%s symlinking files (%s -> %s)\n", - cli_errstr(cli), newname, oldname); + cli_errstr(targetcli), newname, targetname); return 1; } @@ -2230,7 +2385,6 @@ static int cmd_getfacl(void) return 1; } - if (!cli_unix_stat(targetcli, targetname, &sbuf)) { d_printf("%s getfacl doing a stat on file %s\n", cli_errstr(targetcli), src); @@ -2415,7 +2569,7 @@ static int cmd_stat(void) lt = localtime(&sbuf.st_atime); if (lt) { - strftime(mode_str, sizeof(mode_str), "%F %T %z", lt); + strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt); } else { fstrcpy(mode_str, "unknown"); } @@ -2423,7 +2577,7 @@ static int cmd_stat(void) lt = localtime(&sbuf.st_mtime); if (lt) { - strftime(mode_str, sizeof(mode_str), "%F %T %z", lt); + strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt); } else { fstrcpy(mode_str, "unknown"); } @@ -2431,7 +2585,7 @@ static int cmd_stat(void) lt = localtime(&sbuf.st_ctime); if (lt) { - strftime(mode_str, sizeof(mode_str), "%F %T %z", lt); + strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt); } else { fstrcpy(mode_str, "unknown"); } @@ -2472,7 +2626,6 @@ static int cmd_chown(void) return 1; } - if (!SERVER_HAS_UNIX_CIFS(targetcli)) { d_printf("Server doesn't support UNIX CIFS calls.\n"); return 1; @@ -2495,6 +2648,8 @@ static int cmd_rename(void) { pstring src,dest; pstring buf,buf2; + struct cli_state *targetcli; + pstring targetname; pstrcpy(src,cur_dir); pstrcpy(dest,cur_dir); @@ -2508,8 +2663,13 @@ static int cmd_rename(void) pstrcat(src,buf); pstrcat(dest,buf2); - if (!cli_rename(cli, src, dest)) { - d_printf("%s renaming files\n",cli_errstr(cli)); + if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) { + d_printf("chown %s: %s\n", src, cli_errstr(cli)); + return 1; + } + + if (!cli_rename(targetcli, targetname, dest)) { + d_printf("%s renaming files\n",cli_errstr(targetcli)); return 1; } @@ -2602,7 +2762,7 @@ static int cmd_newer(void) if (ok && (sys_stat(buf,&sbuf) == 0)) { newer_than = sbuf.st_mtime; DEBUG(1,("Getting files newer than %s", - time_to_asc(&newer_than))); + time_to_asc(newer_than))); } else { newer_than = 0; } @@ -2738,7 +2898,7 @@ static int cmd_reget(void) return 1; } pstrcpy(local_name, p); - dos_clean_name(remote_name); + clean_name(remote_name); next_token_nr(NULL, local_name, NULL, sizeof(local_name)); @@ -2776,7 +2936,7 @@ static int cmd_reput(void) else pstrcat(remote_name, local_name); - dos_clean_name(remote_name); + clean_name(remote_name); return do_put(remote_name, local_name, True); } @@ -3067,6 +3227,10 @@ static struct {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}}, {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}}, {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}}, + {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}}, + {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}}, + {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}}, + {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}}, {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}}, {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}}, {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}}, diff --git a/source/client/clitar.c b/source/client/clitar.c index f228db11998..7bbb9fc58bf 100644 --- a/source/client/clitar.c +++ b/source/client/clitar.c @@ -652,7 +652,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1) fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE); - dos_clean_name(rname); + clean_name(rname); if (fnum == -1) { DEBUG(0,("%s opening remote file %s (%s)\n", @@ -1650,7 +1650,7 @@ int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind) if (sys_stat(argv[Optind], &stbuf) == 0) { newer_than = stbuf.st_mtime; DEBUG(1,("Getting files newer than %s", - time_to_asc(&newer_than))); + time_to_asc(newer_than))); newOptind++; Optind++; } else { diff --git a/source/client/mount.cifs.c b/source/client/mount.cifs.c index 076001ccc07..7e4c27c820b 100755 --- a/source/client/mount.cifs.c +++ b/source/client/mount.cifs.c @@ -59,6 +59,10 @@ #define MS_MOVE 8192 #endif +#ifndef MS_BIND +#define MS_BIND 4096 +#endif + #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr))) const char *thisprogram; diff --git a/source/client/smbctool.c b/source/client/smbctool.c index b7042f99cb2..2063418a916 100644 --- a/source/client/smbctool.c +++ b/source/client/smbctool.c @@ -368,7 +368,7 @@ static int do_cd(char *newdir) all_string_sub(cur_dir, "/./", "/", 0); /* Format the directory in a libmsmbclient friendly way */ - unix_clean_name(cur_dir); + clean_name(cur_dir); all_string_sub(cur_dir, "/./", "/", 0); pstrcpy(targetpath, "smb:"); pstrcat(targetpath, service); @@ -445,7 +445,7 @@ static void display_finfo(file_info *finfo) finfo->name, attrib_string(finfo->mode), (double)finfo->size, - time_to_asc(&t)); + time_to_asc(t)); dir_total += finfo->size; } } @@ -458,7 +458,7 @@ static void display_stat(char *name, struct stat *st) { time_t t = st->st_mtime; pstring time_str; - pstrcpy(time_str, time_to_asc(&t)); + pstrcpy(time_str, time_to_asc(t)); time_str[strlen(time_str)-1] = 0; d_printf("> %-30s", name); d_printf("%10.10s %8.0f %s\n", *mode_t_string(st->st_mode), (double)st->st_size, time_str); @@ -1130,7 +1130,7 @@ static int cmd_more(void) unlink(lname); return 1; } - dos_clean_name(rname); + clean_name(rname); rc = do_get(rname, lname, False); @@ -2561,7 +2561,7 @@ static int cmd_newer(void) if (ok && (sys_stat(buf,&sbuf) == 0)) { newer_than = sbuf.st_mtime; DEBUG(1,("Getting files newer than %s", - time_to_asc(&newer_than))); + time_to_asc(newer_than))); } else { newer_than = 0; } @@ -2678,7 +2678,7 @@ static int cmd_reget(void) return 1; } pstrcpy(local_name, p); - dos_clean_name(remote_name); + clean_name(remote_name); next_token_nr(NULL, local_name, NULL, sizeof(local_name)); @@ -2716,7 +2716,7 @@ static int cmd_reput(void) else pstrcat(remote_name, local_name); - dos_clean_name(remote_name); + clean_name(remote_name); return do_put(remote_name, local_name, True); } diff --git a/source/configure.in b/source/configure.in index f54c9bd2982..13152f39b24 100644 --- a/source/configure.in +++ b/source/configure.in @@ -299,6 +299,7 @@ AC_SUBST(PAM_MODULES) AC_SUBST(INSTALL_PAM_MODULES) AC_SUBST(UNINSTALL_PAM_MODULES) AC_SUBST(EXTRA_BIN_PROGS) +AC_SUBST(SMBMOUNT_PROGS) AC_SUBST(CIFSMOUNT_PROGS) AC_SUBST(INSTALL_CIFSMOUNT) AC_SUBST(UNINSTALL_CIFSMOUNT) @@ -2966,6 +2967,23 @@ if test x"$samba_cv_HAVE_STAT_ST_BLKSIZE" = x"yes"; then AC_DEFINE(HAVE_STAT_ST_BLKSIZE,1,[Whether the stat struct has a st_blksize property]) fi +AC_CACHE_CHECK([for st_flags in struct stat], + samba_cv_HAVE_STAT_ST_FLAGS, + [ + AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h>], + [struct stat st; st.st_flags = 0;], + samba_cv_HAVE_STAT_ST_FLAGS=yes, + samba_cv_HAVE_STAT_ST_FLAGS=no, + samba_cv_HAVE_STAT_ST_FLAGS=cross) + ]) + +if test x"$samba_cv_HAVE_STAT_ST_FLAGS" = x"yes"; then + AC_DEFINE(HAVE_STAT_ST_FLAGS, 1, + [Whether the stat struct has a st_flags member]) +fi + case "$host_os" in *linux*) AC_CACHE_CHECK([for broken RedHat 7.2 system header files],samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS,[ @@ -3413,6 +3431,7 @@ if test x"$with_ads_support" != x"no"; then CPPFLAGS=$ac_save_CPPFLAGS LDFLAGS=$ac_save_LDFLAGS fi + AC_CHECK_HEADERS(krb5/locate_plugin.h) fi # Now we have determined whether we really want ADS support @@ -3832,6 +3851,20 @@ if test x"$with_ads_support" != x"no"; then [Whether the type krb5_addresses type exists]) fi + AC_CACHE_CHECK([whether krb5_mk_error takes 3 arguments MIT or 9 Heimdal], + samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE, [ + AC_TRY_COMPILE([#include <krb5.h>], + [ + krb5_mk_error(0,0,0);], + samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE=yes, + samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE=no)]) + + if test x"$samba_cv_HAVE_SHORT_KRB5_MK_ERROR_INTERFACE" = x"yes"; then + AC_DEFINE(HAVE_SHORT_KRB5_MK_ERROR_INTERFACE,1, + [whether krb5_mk_error takes 3 arguments MIT or 9 Heimdal]) + fi + + # # # Now the decisions whether we can support krb5 @@ -4017,7 +4050,7 @@ AC_ARG_WITH(smbmount, *linux*) AC_MSG_RESULT(yes) AC_DEFINE(WITH_SMBMOUNT,1,[Whether to build smbmount]) - EXTRA_BIN_PROGS="$EXTRA_BIN_PROGS bin/smbmount bin/smbmnt bin/smbumount" + SMBMOUNT_PROGS="bin/smbmount bin/smbmnt bin/smbumount" ;; *) AC_MSG_ERROR(not on a linux system!) @@ -5571,6 +5604,8 @@ WINBIND_WINS_NSS="nsswitch/libnss_wins.$SHLIBEXT" WINBIND_NSS_LDSHFLAGS=$LDSHFLAGS NSSSONAMEVERSIONSUFFIX="" +SMB_KRB5_LOCATOR="bin/smb_krb5_locator.$SHLIBEXT" + case "$host_os" in *linux*) NSSSONAMEVERSIONSUFFIX=".2" @@ -5640,6 +5675,8 @@ AC_SUBST(WINBIND_NSS_EXTRA_OBJS) AC_SUBST(WINBIND_NSS_EXTRA_LIBS) AC_SUBST(NSSSONAMEVERSIONSUFFIX) +AC_SUBST(SMB_KRB5_LOCATOR) + # Check the setting of --with-winbind AC_ARG_WITH(winbind, diff --git a/source/include/client.h b/source/include/client.h index dc266995c62..aa8a6479470 100644 --- a/source/include/client.h +++ b/source/include/client.h @@ -34,21 +34,6 @@ * These definitions depend on smb.h */ -typedef struct file_info -{ - SMB_BIG_UINT size; - uint16 mode; - uid_t uid; - gid_t gid; - /* these times are normally kept in GMT */ - struct timespec mtime_ts; - struct timespec atime_ts; - struct timespec ctime_ts; - pstring name; - pstring dir; - char short_name[13*3]; /* the *3 is to cope with multi-byte */ -} file_info; - struct print_job_info { uint16 id; @@ -173,6 +158,21 @@ struct cli_state { BOOL case_sensitive; /* False by default. */ }; +typedef struct file_info { + struct cli_state *cli; + SMB_BIG_UINT size; + uint16 mode; + uid_t uid; + gid_t gid; + /* these times are normally kept in GMT */ + struct timespec mtime_ts; + struct timespec atime_ts; + struct timespec ctime_ts; + pstring name; + pstring dir; + char short_name[13*3]; /* the *3 is to cope with multi-byte */ +} file_info; + #define CLI_FULL_CONNECTION_DONT_SPNEGO 0x0001 #define CLI_FULL_CONNECTION_USE_KERBEROS 0x0002 #define CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK 0x0004 diff --git a/source/include/doserr.h b/source/include/doserr.h index 4e3a85ff73f..3c3978a5b9f 100644 --- a/source/include/doserr.h +++ b/source/include/doserr.h @@ -202,6 +202,7 @@ #define WERR_SERVICE_NEVER_STARTED W_ERROR(1077) #define WERR_MACHINE_LOCKED W_ERROR(1271) #define WERR_NO_LOGON_SERVERS W_ERROR(1311) +#define WERR_LOGON_FAILURE W_ERROR(1326) #define WERR_NO_SUCH_DOMAIN W_ERROR(1355) #define WERR_INVALID_SECURITY_DESCRIPTOR W_ERROR(1338) #define WERR_TIME_SKEW W_ERROR(1398) diff --git a/source/include/includes.h b/source/include/includes.h index 34b9c36c8ac..bdd92f219ee 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -1181,6 +1181,10 @@ krb5_error_code handle_krberror_packet(krb5_context context, krb5_data *packet); void krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opt); krb5_error_code krb5_get_init_creds_opt_alloc(krb5_context context, krb5_get_init_creds_opt **opt); +krb5_error_code smb_krb5_mk_error(krb5_context context, + krb5_error_code error_code, + const krb5_principal server, + krb5_data *reply); #endif /* HAVE_KRB5 */ diff --git a/source/include/msdfs.h b/source/include/msdfs.h index 4e3487de0f4..05cfe4e102f 100644 --- a/source/include/msdfs.h +++ b/source/include/msdfs.h @@ -51,7 +51,7 @@ struct referral { }; struct junction_map { - pstring service_name; + fstring service_name; pstring volume_name; pstring comment; int referral_count; @@ -59,31 +59,12 @@ struct junction_map { }; struct dfs_path { - pstring hostname; - pstring servicename; + fstring hostname; + fstring servicename; pstring reqpath; + BOOL posix_path; }; -#define RESOLVE_DFSPATH(name, conn, inbuf, outbuf) \ -{ if ((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && \ - lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) && \ - dfs_redirect(name, conn, False)) \ - return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, \ - ERRSRV, ERRbadpath);; } - -#define RESOLVE_DFSPATH_STATUS(name, conn, inbuf, outbuf) \ -{ if ((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && \ - lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) && \ - dfs_redirect(name, conn, False)) \ - return NT_STATUS_PATH_NOT_COVERED;; } - -#define RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf) \ -{ if ((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && \ - lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) && \ - dfs_redirect(name,conn, True)) \ - return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, \ - ERRSRV, ERRbadpath);; } - #define init_dfsroot(conn, inbuf, outbuf) \ { if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) { \ DEBUG(2,("Serving %s as a Dfs root\n", \ diff --git a/source/include/nt_printing.h b/source/include/nt_printing.h index 5bd64ae7be3..c2dde7d4785 100644 --- a/source/include/nt_printing.h +++ b/source/include/nt_printing.h @@ -386,18 +386,13 @@ typedef struct { #define NE_HEADER_MAJOR_VER_OFFSET 63 /* Portable Executable format */ -#define PE_HEADER_SIZE 248 +#define PE_HEADER_SIZE 24 #define PE_HEADER_SIGNATURE_OFFSET 0 #define PE_HEADER_SIGNATURE 0x00004550 #define PE_HEADER_MACHINE_OFFSET 4 #define PE_HEADER_MACHINE_I386 0x14c #define PE_HEADER_NUMBER_OF_SECTIONS 6 -#define PE_HEADER_MAJOR_OS_VER_OFFSET 64 -#define PE_HEADER_MINOR_OS_VER_OFFSET 66 -#define PE_HEADER_MAJOR_IMG_VER_OFFSET 68 -#define PE_HEADER_MINOR_IMG_VER_OFFSET 70 -#define PE_HEADER_MAJOR_SS_VER_OFFSET 72 -#define PE_HEADER_MINOR_SS_VER_OFFSET 74 +#define PE_HEADER_OPTIONAL_HEADER_SIZE 20 #define PE_HEADER_SECT_HEADER_SIZE 40 #define PE_HEADER_SECT_NAME_OFFSET 0 #define PE_HEADER_SECT_SIZE_DATA_OFFSET 16 diff --git a/source/include/rpc_secdes.h b/source/include/rpc_secdes.h index 9e65052f849..6bfddcef01f 100644 --- a/source/include/rpc_secdes.h +++ b/source/include/rpc_secdes.h @@ -195,6 +195,7 @@ typedef struct standard_mapping { /* Combinations of standard masks. */ #define STANDARD_RIGHTS_ALL_ACCESS STD_RIGHT_ALL_ACCESS /* 0x001f0000 */ +#define STANDARD_RIGHTS_MODIFY_ACCESS STD_RIGHT_READ_CONTROL_ACCESS /* 0x00020000 */ #define STANDARD_RIGHTS_EXECUTE_ACCESS STD_RIGHT_READ_CONTROL_ACCESS /* 0x00020000 */ #define STANDARD_RIGHTS_READ_ACCESS STD_RIGHT_READ_CONTROL_ACCESS /* 0x00020000 */ #define STANDARD_RIGHTS_WRITE_ACCESS \ @@ -243,10 +244,23 @@ typedef struct standard_mapping { #define GENERIC_RIGHTS_FILE_EXECUTE \ (STANDARD_RIGHTS_EXECUTE_ACCESS | \ + STD_RIGHT_SYNCHRONIZE_ACCESS | \ SA_RIGHT_FILE_READ_ATTRIBUTES | \ SA_RIGHT_FILE_EXECUTE) - +#define GENERIC_RIGHTS_FILE_MODIFY \ + (STANDARD_RIGHTS_MODIFY_ACCESS | \ + STD_RIGHT_SYNCHRONIZE_ACCESS | \ + STD_RIGHT_DELETE_ACCESS | \ + SA_RIGHT_FILE_WRITE_ATTRIBUTES | \ + SA_RIGHT_FILE_READ_ATTRIBUTES | \ + SA_RIGHT_FILE_EXECUTE | \ + SA_RIGHT_FILE_WRITE_EA | \ + SA_RIGHT_FILE_READ_EA | \ + SA_RIGHT_FILE_APPEND_DATA | \ + SA_RIGHT_FILE_WRITE_DATA | \ + SA_RIGHT_FILE_READ_DATA) + /* SAM server specific access rights */ #define SA_RIGHT_SAM_CONNECT_SERVER 0x00000001 diff --git a/source/include/rpc_srvsvc.h b/source/include/rpc_srvsvc.h index 5d32d65c3df..62acce58050 100644 --- a/source/include/rpc_srvsvc.h +++ b/source/include/rpc_srvsvc.h @@ -5,6 +5,8 @@ Copyright (C) Luke Kenneth Casson Leighton 1996-1997 Copyright (C) Paul Ashton 1997 Copyright (C) Nigel Williams 2001 + Copyright (C) Gerald (Jerry) Carter 2006. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -72,128 +74,84 @@ typedef struct net_srv_disk_enum { WERROR status; /* return status */ } SRV_Q_NET_DISK_ENUM, SRV_R_NET_DISK_ENUM; -typedef struct net_name_validate { - uint32 ptr_srv_name; - UNISTR2 uni_srv_name; - UNISTR2 uni_name; /*name to validate*/ +/***************************/ + +typedef struct { + UNISTR2 *servername; + UNISTR2 sharename; uint32 type; uint32 flags; WERROR status; -} SRV_Q_NET_NAME_VALIDATE, SRV_R_NET_NAME_VALIDATE; - -/* SESS_INFO_0 (pointers to level 0 session info strings) */ -typedef struct ptr_sess_info0 -{ - uint32 ptr_name; /* pointer to name. */ - -} SESS_INFO_0; +} SRV_Q_NET_NAME_VALIDATE; -/* SESS_INFO_0_STR (level 0 session info strings) */ -typedef struct str_sess_info0 -{ - UNISTR2 uni_name; /* unicode string of name */ +typedef struct { + WERROR status; +} SRV_R_NET_NAME_VALIDATE; -} SESS_INFO_0_STR; +/***************************/ /* oops - this is going to take up a *massive* amount of stack. */ /* the UNISTR2s already have 1024 uint16 chars in them... */ -#define MAX_SESS_ENTRIES 32 -/* SRV_SESS_INFO_0 */ -typedef struct srv_sess_info_0_info -{ - uint32 num_entries_read; /* EntriesRead */ - uint32 ptr_sess_info; /* Buffer */ - uint32 num_entries_read2; /* EntriesRead */ +#define MAX_SESS_ENTRIES 32 - SESS_INFO_0 info_0 [MAX_SESS_ENTRIES]; /* session entry pointers */ - SESS_INFO_0_STR info_0_str[MAX_SESS_ENTRIES]; /* session entry strings */ +typedef struct { + UNISTR2 *sharename; +} SESS_INFO_0; +typedef struct { + uint32 num_entries_read; + uint32 ptr_sess_info; + uint32 num_entries_read2; + SESS_INFO_0 info_0[MAX_SESS_ENTRIES]; } SRV_SESS_INFO_0; -/* SESS_INFO_1 (pointers to level 1 session info strings) */ -typedef struct ptr_sess_info1 -{ - uint32 ptr_name; /* pointer to name. */ - uint32 ptr_user; /* pointer to user name. */ - +typedef struct { + UNISTR2 *sharename; + UNISTR2 *username; uint32 num_opens; uint32 open_time; uint32 idle_time; uint32 user_flags; - } SESS_INFO_1; -/* SESS_INFO_1_STR (level 1 session info strings) */ -typedef struct str_sess_info1 -{ - UNISTR2 uni_name; /* unicode string of name */ - UNISTR2 uni_user; /* unicode string of user */ - -} SESS_INFO_1_STR; - -/* SRV_SESS_INFO_1 */ -typedef struct srv_sess_info_1_info -{ - uint32 num_entries_read; /* EntriesRead */ - uint32 ptr_sess_info; /* Buffer */ - uint32 num_entries_read2; /* EntriesRead */ - - SESS_INFO_1 info_1 [MAX_SESS_ENTRIES]; /* session entry pointers */ - SESS_INFO_1_STR info_1_str[MAX_SESS_ENTRIES]; /* session entry strings */ - +typedef struct { + uint32 num_entries_read; + uint32 ptr_sess_info; + uint32 num_entries_read2; + SESS_INFO_1 info_1[MAX_SESS_ENTRIES]; } SRV_SESS_INFO_1; -/* SRV_SESS_INFO_CTR */ -typedef struct srv_sess_info_ctr_info -{ - uint32 switch_value; /* switch value */ - uint32 ptr_sess_ctr; /* pointer to sess info union */ - union - { - SRV_SESS_INFO_0 info0; /* session info level 0 */ - SRV_SESS_INFO_1 info1; /* session info level 1 */ - - } sess; +typedef struct { + uint32 switch_value; + uint32 ptr_sess_ctr; + union { + SRV_SESS_INFO_0 info0; + SRV_SESS_INFO_1 info1; + } sess; } SRV_SESS_INFO_CTR; - -/* SRV_Q_NET_SESS_ENUM */ -typedef struct q_net_sess_enum_info -{ - uint32 ptr_srv_name; /* pointer (to server name?) */ - UNISTR2 uni_srv_name; /* server name */ - - uint32 ptr_qual_name; /* pointer (to qualifier name) */ - UNISTR2 uni_qual_name; /* qualifier name "\\qualifier" */ - - uint32 ptr_user_name; /* pointer (to user name */ - UNISTR2 uni_user_name; /* user name */ - - uint32 sess_level; /* session level */ - +typedef struct { + UNISTR2 *servername; + UNISTR2 *qualifier; + UNISTR2 *username; + uint32 sess_level; SRV_SESS_INFO_CTR *ctr; - - uint32 preferred_len; /* preferred maximum length (0xffff ffff) */ + uint32 preferred_len; ENUM_HND enum_hnd; - } SRV_Q_NET_SESS_ENUM; -/* SRV_R_NET_SESS_ENUM */ -typedef struct r_net_sess_enum_info -{ - uint32 sess_level; /* share level */ - +typedef struct { + uint32 sess_level; SRV_SESS_INFO_CTR *ctr; - - uint32 total_entries; /* total number of entries */ + uint32 total_entries; ENUM_HND enum_hnd; - - WERROR status; /* return status */ - + WERROR status; } SRV_R_NET_SESS_ENUM; +/***************************/ + /* SRV_Q_NET_SESS_DEL */ typedef struct q_net_sess_del { @@ -685,104 +643,47 @@ typedef struct r_net_share_del } SRV_R_NET_SHARE_DEL; -/* FILE_INFO_3 (level 3 file info strings) */ -typedef struct file_info3_info -{ +/***************************/ + +typedef struct { uint32 id; /* file index */ uint32 perms; /* file permissions. don't know what format */ uint32 num_locks; /* file locks */ - uint32 ptr_path_name; /* file name */ - uint32 ptr_user_name; /* file owner */ - + UNISTR2 *path; /* file name */ + UNISTR2 *user; /* file owner */ } FILE_INFO_3; -/* FILE_INFO_3_STR (level 3 file info strings) */ -typedef struct str_file_info3_info -{ - UNISTR2 uni_path_name; /* unicode string of file name */ - UNISTR2 uni_user_name; /* unicode string of file owner. */ - -} FILE_INFO_3_STR; - -/* SRV_FILE_INFO_3 */ -typedef struct srv_file_info_3 -{ - uint32 num_entries_read; /* EntriesRead */ - uint32 ptr_file_info; /* Buffer */ - - uint32 num_entries_read2; /* EntriesRead */ - FILE_INFO_3 info_3; /* file entry details */ - FILE_INFO_3_STR info_3_str; /* file entry strings */ -} SRV_FILE_INFO_3; - -/* SRV_FILE_INFO_CTR */ -typedef struct srv_file_info_3_info -{ - uint32 switch_value; /* switch value */ +typedef struct { + uint32 level; /* switch value */ uint32 ptr_file_info; /* pointer to file info union */ uint32 num_entries; uint32 ptr_entries; uint32 num_entries2; - union - { - SRV_FILE_INFO_3 *info3; + union { + FILE_INFO_3 *info3; } file; } SRV_FILE_INFO_CTR; - -/* SRV_Q_NET_FILE_ENUM */ -typedef struct q_net_file_enum_info -{ - uint32 ptr_srv_name; /* pointer (to server name?) */ - UNISTR2 uni_srv_name; /* server name */ - - uint32 ptr_qual_name; /* pointer (to qualifier name) */ - UNISTR2 uni_qual_name; /* qualifier name "\\qualifier" */ - - uint32 ptr_user_name; /* pointer (to user name) */ - UNISTR2 uni_user_name; /* user name */ - - uint32 file_level; /* file level */ - +typedef struct { + UNISTR2 *servername; + UNISTR2 *qualifier; + UNISTR2 *username; + uint32 level; SRV_FILE_INFO_CTR ctr; - - uint32 preferred_len; /* preferred maximum length (0xffff ffff) */ + uint32 preferred_len; /* preferred maximum length (0xffff ffff) */ ENUM_HND enum_hnd; - } SRV_Q_NET_FILE_ENUM; - -/* SRV_R_NET_FILE_ENUM */ -typedef struct r_net_file_enum_info -{ - uint32 file_level; /* file level */ - +typedef struct { + uint32 level; SRV_FILE_INFO_CTR ctr; - - uint32 total_entries; /* total number of files */ + uint32 total_entries; ENUM_HND enum_hnd; - - WERROR status; /* return status */ - + WERROR status; } SRV_R_NET_FILE_ENUM; -/* SRV_Q_NET_FILE_CLOSE */ -typedef struct q_net_file_close -{ - uint32 ptr_srv_name; /* pointer to server name */ - UNISTR2 uni_srv_name; /* server name */ - - uint32 file_id; -} SRV_Q_NET_FILE_CLOSE; - -/* SRV_R_NET_FILE_CLOSE */ -typedef struct r_net_file_close -{ - WERROR status; /* return status */ -} SRV_R_NET_FILE_CLOSE; - /* SRV_INFO_100 */ typedef struct srv_info_100_info { @@ -967,4 +868,17 @@ typedef struct r_net_file_set_secdesc WERROR status; } SRV_R_NET_FILE_SET_SECDESC; +/***************************/ + +typedef struct { + UNISTR2 *servername; + uint32 file_id; +} SRV_Q_NET_FILE_CLOSE; + +typedef struct { + WERROR status; +} SRV_R_NET_FILE_CLOSE; + +/***************************/ + #endif /* _RPC_SRVSVC_H */ diff --git a/source/include/smb.h b/source/include/smb.h index 3f0356f2248..a8fb39797b2 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -500,12 +500,13 @@ typedef struct files_struct { uint32 access_mask; /* NTCreateX access bits (FILE_READ_DATA etc.) */ uint32 share_access; /* NTCreateX share constants (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE). */ BOOL pending_modtime_owner; - time_t pending_modtime; - time_t last_write_time; + struct timespec pending_modtime; + struct timespec last_write_time; int oplock_type; int sent_oplock_break; struct timed_event *oplock_timeout; struct lock_struct last_lock_failure; + int current_lock_count; /* Count the number of outstanding locks and pending locks. */ struct share_mode_entry *pending_break_messages; int num_pending_break_messages; diff --git a/source/include/smbprofile.h b/source/include/smbprofile.h index fa7c6e4a5ae..cc501739c16 100644 --- a/source/include/smbprofile.h +++ b/source/include/smbprofile.h @@ -152,9 +152,9 @@ enum profile_stats_values #define syscall_getwd_count __profile_stats_value(PR_VALUE_SYSCALL_GETWD, count) #define syscall_getwd_time __profile_stats_value(PR_VALUE_SYSCALL_GETWD, time) - PR_VALUE_SYSCALL_UTIME, -#define syscall_utime_count __profile_stats_value(PR_VALUE_SYSCALL_UTIME, count) -#define syscall_utime_time __profile_stats_value(PR_VALUE_SYSCALL_UTIME, time) + PR_VALUE_SYSCALL_NTIMES, +#define syscall_ntimes_count __profile_stats_value(PR_VALUE_SYSCALL_NTIMES, count) +#define syscall_ntimes_time __profile_stats_value(PR_VALUE_SYSCALL_NTIMES, time) PR_VALUE_SYSCALL_FTRUNCATE, #define syscall_ftruncate_count __profile_stats_value(PR_VALUE_SYSCALL_FTRUNCATE, count) diff --git a/source/include/trans2.h b/source/include/trans2.h index 5b9623e3d40..c7faf4f63f6 100644 --- a/source/include/trans2.h +++ b/source/include/trans2.h @@ -1,6 +1,8 @@ /* Unix SMB/CIFS implementation. SMB transaction2 handling + + Copyright (C) James Peach 2007 Copyright (C) Jeremy Allison 1994-2002. Extensively modified by Andrew Tridgell, 1995 @@ -352,6 +354,7 @@ Byte offset Type name description #define SMB_QUERY_FILE_UNIX_BASIC 0x200 /* UNIX File Info*/ #define SMB_SET_FILE_UNIX_BASIC 0x200 +#define SMB_SET_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */ #define SMB_MODE_NO_CHANGE 0xFFFFFFFF /* file mode value which */ /* means "don't change it" */ @@ -435,6 +438,18 @@ Offset Size Name #define UNIX_EXTRA_MASK 0007000 #define UNIX_ALL_MASK 0007777 +/* Flags for chflags (CIFS_UNIX_EXTATTR_CAP capability) and + * SMB_QUERY_FILE_UNIX_INFO2. + */ +#define EXT_SECURE_DELETE 0x00000001 +#define EXT_ENABLE_UNDELETE 0x00000002 +#define EXT_SYNCHRONOUS 0x00000004 +#define EXT_IMMUTABLE 0x00000008 +#define EXT_OPEN_APPEND_ONLY 0x00000010 +#define EXT_DO_NOT_BACKUP 0x00000020 +#define EXT_NO_UPDATE_ATIME 0x00000040 +#define EXT_HIDDEN 0x00000080 + #define SMB_QUERY_FILE_UNIX_LINK 0x201 #define SMB_SET_FILE_UNIX_LINK 0x201 #define SMB_SET_FILE_UNIX_HLINK 0x203 @@ -455,8 +470,35 @@ Offset Size Name #define SMB_QUERY_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */ #define SMB_SET_FILE_UNIX_INFO2 0x20B +/* +SMB_QUERY_FILE_UNIX_INFO2 is SMB_QUERY_FILE_UNIX_BASIC with create +time and file flags appended. The corresponding info level for +findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2. + Size Offset Value + --------------------- + 0 LARGE_INTEGER EndOfFile File size + 8 LARGE_INTEGER Blocks Number of blocks used on disk + 16 LARGE_INTEGER ChangeTime Attribute change time + 24 LARGE_INTEGER LastAccessTime Last access time + 32 LARGE_INTEGER LastModificationTime Last modification time + 40 LARGE_INTEGER Uid Numeric user id for the owner + 48 LARGE_INTEGER Gid Numeric group id of owner + 56 ULONG Type Enumeration specifying the file type + 60 LARGE_INTEGER devmajor Major device number if type is device + 68 LARGE_INTEGER devminor Minor device number if type is device + 76 LARGE_INTEGER uniqueid This is a server-assigned unique id + 84 LARGE_INTEGER permissions Standard UNIX permissions + 92 LARGE_INTEGER nlinks Number of hard links + 100 LARGE_INTEGER CreationTime Create/birth time + 108 ULONG FileFlags File flags enumeration + 112 ULONG FileFlagsMask Mask of valid flags +*/ + /* Transact 2 Find First levels */ #define SMB_FIND_FILE_UNIX 0x202 +#define SMB_FIND_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */ + +#define SMB_FILE_UNIX_INFO2_SIZE 116 /* Info level for TRANS2_QFSINFO - returns version of CIFS UNIX extensions, plus @@ -564,6 +606,37 @@ number of entries sent will be zero. */ +#define SMB_QUERY_POSIX_WHOAMI 0x202 + +enum smb_whoami_flags { + SMB_WHOAMI_GUEST = 0x1 /* Logged in as (or squashed to) guest */ +}; + +/* Mask of which WHOAMI bits are valid. This should make it easier for clients + * to cope with servers that have different sets of WHOAMI flags (as more get + * added). + */ +#define SMB_WHOAMI_MASK 0x00000001 + +/* + SMBWhoami - Query the user mapping performed by the server for the + connected tree. This is a subcommand of the TRANS2_QFSINFO. + + Returns: + 4 bytes unsigned - mapping flags (smb_whoami_flags) + 4 bytes unsigned - flags mask + + 8 bytes unsigned - primary UID + 8 bytes unsigned - primary GID + 4 bytes unsigned - number of supplementary GIDs + 4 bytes unsigned - number of SIDs + 4 bytes unsigned - SID list byte count + 4 bytes - pad / reserved (must be zero) + + 8 bytes unsigned[] - list of GIDs (may be empty) + DOM_SID[] - list of SIDs (may be empty) +*/ + /* The query/set info levels for POSIX ACLs. */ #define SMB_QUERY_POSIX_ACL 0x204 #define SMB_SET_POSIX_ACL 0x204 @@ -589,7 +662,7 @@ number of entries sent will be zero. #define SMB_POSIX_IGNORE_ACE_ENTRIES 0xFFFF -/* Definition of parameter block of SMB_SET_POSIX_LOCK */ +/* Definition of data block of SMB_SET_POSIX_LOCK */ /* [2 bytes] lock_type - 0 = Read, 1 = Write, 2 = Unlock [2 bytes] lock_flags - 1 = Wait (only valid for setlock) @@ -628,11 +701,11 @@ number of entries sent will be zero. #define SMB_O_NOFOLLOW 0x400 #define SMB_O_DIRECT 0x800 -/* Definition of request parameter block for SMB_POSIX_PATH_OPEN */ +/* Definition of request data block for SMB_POSIX_PATH_OPEN */ /* [4 bytes] flags (as smb_ntcreate_Flags). - [4 bytes] open_mode - [4 bytes] mode_t - same encoding as "Standard UNIX permissions" above. + [4 bytes] open_mode - SMB_O_xxx flags above. + [8 bytes] mode_t (permissions) - same encoding as "Standard UNIX permissions" above in SMB_SET_FILE_UNIX_BASIC. [2 bytes] ret_info_level - optimization. Info level to be returned. */ @@ -641,8 +714,20 @@ number of entries sent will be zero. #define SMB_NO_INFO_LEVEL_RETURNED 0xFFFF /* - [2 bytes] reply info level - as requested or 0xFFFF if not available. + [2 bytes] - flags field. Identical to flags reply for oplock response field in SMBNTCreateX) + [2 bytes] - FID returned. + [4 bytes] - CreateAction (same as in NTCreateX response). + [2 bytes] - reply info level - as requested or 0xFFFF if not available. + [2 bytes] - padding (must be zero) [n bytes] - info level reply - if available. */ +/* Definition of request data block for SMB_POSIX_UNLINK */ +/* + [2 bytes] flags (defined below). +*/ + +#define SMB_POSIX_UNLINK_FILE_TARGET 0 +#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1 + #endif diff --git a/source/include/vfs.h b/source/include/vfs.h index 2d04a374c4c..29e96f6b506 100644 --- a/source/include/vfs.h +++ b/source/include/vfs.h @@ -67,7 +67,10 @@ Also include kernel_flock call - jmcd */ /* Changed to version 19, kernel change notify has been merged Also included linux setlease call - jmcd */ -#define SMB_VFS_INTERFACE_VERSION 19 +/* Changed to version 20, use ntimes call instead of utime (greater + * timestamp resolition. JRA. */ +/* Changed to version21 to add chflags operation -- jpeach */ +#define SMB_VFS_INTERFACE_VERSION 21 /* to bug old modules which are trying to compile with the old functions */ @@ -144,7 +147,7 @@ typedef enum _vfs_op_type { SMB_VFS_OP_FCHOWN, SMB_VFS_OP_CHDIR, SMB_VFS_OP_GETWD, - SMB_VFS_OP_UTIME, + SMB_VFS_OP_NTIMES, SMB_VFS_OP_FTRUNCATE, SMB_VFS_OP_LOCK, SMB_VFS_OP_KERNEL_FLOCK, @@ -156,6 +159,7 @@ typedef enum _vfs_op_type { SMB_VFS_OP_MKNOD, SMB_VFS_OP_REALPATH, SMB_VFS_OP_NOTIFY_WATCH, + SMB_VFS_OP_CHFLAGS, /* NT ACL operations. */ @@ -269,7 +273,7 @@ struct vfs_ops { int (*fchown)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, uid_t uid, gid_t gid); int (*chdir)(struct vfs_handle_struct *handle, const char *path); char *(*getwd)(struct vfs_handle_struct *handle, char *buf); - int (*utime)(struct vfs_handle_struct *handle, const char *path, struct utimbuf *times); + int (*ntimes)(struct vfs_handle_struct *handle, const char *path, const struct timespec ts[2]); int (*ftruncate)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_OFF_T offset); BOOL (*lock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type); int (*kernel_flock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, uint32 share_mode); @@ -287,6 +291,7 @@ struct vfs_ops { void *private_data, struct notify_event *ev), void *private_data, void *handle_p); + int (*chflags)(struct vfs_handle_struct *handle, const char *path, uint flags); /* NT ACL operations. */ @@ -392,7 +397,7 @@ struct vfs_ops { struct vfs_handle_struct *fchown; struct vfs_handle_struct *chdir; struct vfs_handle_struct *getwd; - struct vfs_handle_struct *utime; + struct vfs_handle_struct *ntimes; struct vfs_handle_struct *ftruncate; struct vfs_handle_struct *lock; struct vfs_handle_struct *kernel_flock; @@ -404,6 +409,7 @@ struct vfs_ops { struct vfs_handle_struct *mknod; struct vfs_handle_struct *realpath; struct vfs_handle_struct *notify_watch; + struct vfs_handle_struct *chflags; /* NT ACL operations. */ diff --git a/source/include/vfs_macros.h b/source/include/vfs_macros.h index f50da3a02b5..2ff313b42ce 100644 --- a/source/include/vfs_macros.h +++ b/source/include/vfs_macros.h @@ -67,7 +67,7 @@ #define SMB_VFS_FCHOWN(fsp, fd, uid, gid) ((fsp)->conn->vfs.ops.fchown((fsp)->conn->vfs.handles.fchown, (fsp), (fd), (uid), (gid))) #define SMB_VFS_CHDIR(conn, path) ((conn)->vfs.ops.chdir((conn)->vfs.handles.chdir, (path))) #define SMB_VFS_GETWD(conn, buf) ((conn)->vfs.ops.getwd((conn)->vfs.handles.getwd, (buf))) -#define SMB_VFS_UTIME(conn, path, times) ((conn)->vfs.ops.utime((conn)->vfs.handles.utime, (path), (times))) +#define SMB_VFS_NTIMES(conn, path, ts) ((conn)->vfs.ops.ntimes((conn)->vfs.handles.ntimes, (path), (ts))) #define SMB_VFS_FTRUNCATE(fsp, fd, offset) ((fsp)->conn->vfs.ops.ftruncate((fsp)->conn->vfs.handles.ftruncate, (fsp), (fd), (offset))) #define SMB_VFS_LOCK(fsp, fd, op, offset, count, type) ((fsp)->conn->vfs.ops.lock((fsp)->conn->vfs.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type))) #define SMB_VFS_KERNEL_FLOCK(fsp, fd, share_mode) ((fsp)->conn->vfs.ops.kernel_flock((fsp)->conn->vfs.handles.kernel_flock, (fsp), (fd), (share_mode))) @@ -79,6 +79,7 @@ #define SMB_VFS_MKNOD(conn, path, mode, dev) ((conn)->vfs.ops.mknod((conn)->vfs.handles.mknod, (path), (mode), (dev))) #define SMB_VFS_REALPATH(conn, path, resolved_path) ((conn)->vfs.ops.realpath((conn)->vfs.handles.realpath, (path), (resolved_path))) #define SMB_VFS_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs.ops.notify_watch((conn)->vfs.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p))) +#define SMB_VFS_CHFLAGS(conn, path, flags) ((conn)->vfs.ops.chflags((conn)->vfs.handles.chflags, (path), (flags))) /* NT ACL operations. */ #define SMB_VFS_FGET_NT_ACL(fsp, fd, security_info, ppdesc) ((fsp)->conn->vfs.ops.fget_nt_acl((fsp)->conn->vfs.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc))) @@ -182,7 +183,7 @@ #define SMB_VFS_OPAQUE_FCHOWN(fsp, fd, uid, gid) ((fsp)->conn->vfs_opaque.ops.fchown((fsp)->conn->vfs_opaque.handles.fchown, (fsp), (fd), (uid), (gid))) #define SMB_VFS_OPAQUE_CHDIR(conn, path) ((conn)->vfs_opaque.ops.chdir((conn)->vfs_opaque.handles.chdir, (path))) #define SMB_VFS_OPAQUE_GETWD(conn, buf) ((conn)->vfs_opaque.ops.getwd((conn)->vfs_opaque.handles.getwd, (buf))) -#define SMB_VFS_OPAQUE_UTIME(conn, path, times) ((conn)->vfs_opaque.ops.utime((conn)->vfs_opaque.handles.utime, (path), (times))) +#define SMB_VFS_OPAQUE_NTIMES(conn, path, ts) ((conn)->vfs_opaque.ops.ntimes((conn)->vfs_opaque.handles.ntimes, (path), (ts))) #define SMB_VFS_OPAQUE_FTRUNCATE(fsp, fd, offset) ((fsp)->conn->vfs_opaque.ops.ftruncate((fsp)->conn->vfs_opaque.handles.ftruncate, (fsp), (fd), (offset))) #define SMB_VFS_OPAQUE_LOCK(fsp, fd, op, offset, count, type) ((fsp)->conn->vfs_opaque.ops.lock((fsp)->conn->vfs_opaque.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type))) #define SMB_VFS_OPAQUE_FLOCK(fsp, fd, share_mode) ((fsp)->conn->vfs_opaque.ops.lock((fsp)->conn->vfs_opaque.handles.kernel_flock, (fsp), (fd), (share_mode))) @@ -194,6 +195,7 @@ #define SMB_VFS_OPAQUE_MKNOD(conn, path, mode, dev) ((conn)->vfs_opaque.ops.mknod((conn)->vfs_opaque.handles.mknod, (path), (mode), (dev))) #define SMB_VFS_OPAQUE_REALPATH(conn, path, resolved_path) ((conn)->vfs_opaque.ops.realpath((conn)->vfs_opaque.handles.realpath, (path), (resolved_path))) #define SMB_VFS_OPAQUE_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_opaque.ops.notify_watch((conn)->vfs_opaque.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p))) +#define SMB_VFS_OPAQUE_CHFLAGS(conn, path, flags) ((conn)->vfs_opaque.ops.chflags((conn)->vfs_opaque.handles.chflags, (path), (flags))) /* NT ACL operations. */ #define SMB_VFS_OPAQUE_FGET_NT_ACL(fsp, fd, security_info, ppdesc) ((fsp)->conn->vfs_opaque.ops.fget_nt_acl((fsp)->conn->vfs_opaque.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc))) @@ -298,7 +300,7 @@ #define SMB_VFS_NEXT_FCHOWN(handle, fsp, fd, uid, gid) ((handle)->vfs_next.ops.fchown((handle)->vfs_next.handles.fchown, (fsp), (fd), (uid), (gid))) #define SMB_VFS_NEXT_CHDIR(handle, path) ((handle)->vfs_next.ops.chdir((handle)->vfs_next.handles.chdir, (path))) #define SMB_VFS_NEXT_GETWD(handle, buf) ((handle)->vfs_next.ops.getwd((handle)->vfs_next.handles.getwd, (buf))) -#define SMB_VFS_NEXT_UTIME(handle, path, times) ((handle)->vfs_next.ops.utime((handle)->vfs_next.handles.utime, (path), (times))) +#define SMB_VFS_NEXT_NTIMES(handle, path, ts) ((handle)->vfs_next.ops.ntimes((handle)->vfs_next.handles.ntimes, (path), (ts))) #define SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, offset) ((handle)->vfs_next.ops.ftruncate((handle)->vfs_next.handles.ftruncate, (fsp), (fd), (offset))) #define SMB_VFS_NEXT_LOCK(handle, fsp, fd, op, offset, count, type) ((handle)->vfs_next.ops.lock((handle)->vfs_next.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type))) #define SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, fd, share_mode)((handle)->vfs_next.ops.kernel_flock((handle)->vfs_next.handles.kernel_flock, (fsp), (fd), (share_mode))) @@ -310,6 +312,7 @@ #define SMB_VFS_NEXT_MKNOD(handle, path, mode, dev) ((handle)->vfs_next.ops.mknod((handle)->vfs_next.handles.mknod, (path), (mode), (dev))) #define SMB_VFS_NEXT_REALPATH(handle, path, resolved_path) ((handle)->vfs_next.ops.realpath((handle)->vfs_next.handles.realpath, (path), (resolved_path))) #define SMB_VFS_NEXT_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_next.ops.notify_watch((conn)->vfs_next.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p))) +#define SMB_VFS_NEXT_CHFLAGS(handle, path, flags) ((handle)->vfs_next.ops.chflags((handle)->vfs_next.handles.chflags, (path), (flags))) /* NT ACL operations. */ #define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, fd, security_info, ppdesc) ((handle)->vfs_next.ops.fget_nt_acl((handle)->vfs_next.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc))) diff --git a/source/lib/debug.c b/source/lib/debug.c index 5f141661106..62fda5741c9 100644 --- a/source/lib/debug.c +++ b/source/lib/debug.c @@ -962,7 +962,7 @@ BOOL dbghdr( int level, const char *file, const char *func, int line ) /* Print the header if timestamps are turned on. If parameters are * not yet loaded, then default to timestamps on. */ - if( lp_timestamp_logs() || !(lp_loaded()) ) { + if( lp_timestamp_logs() || lp_debug_prefix_timestamp() || !(lp_loaded()) ) { char header_str[200]; header_str[0] = '\0'; @@ -980,9 +980,15 @@ BOOL dbghdr( int level, const char *file, const char *func, int line ) } /* Print it all out at once to prevent split syslog output. */ - (void)Debug1( "[%s, %d%s] %s:%s(%d)\n", + if( lp_debug_prefix_timestamp() ) { + (void)Debug1( "[%s, %d%s] ", + current_timestring(lp_debug_hires_timestamp()), level, + header_str); + } else { + (void)Debug1( "[%s, %d%s] %s:%s(%d)\n", current_timestring(lp_debug_hires_timestamp()), level, header_str, file, func, line ); + } } errno = old_errno; diff --git a/source/lib/interface.c b/source/lib/interface.c index 9d0b966390f..e2c9294b281 100644 --- a/source/lib/interface.c +++ b/source/lib/interface.c @@ -231,6 +231,18 @@ void load_interfaces(void) } +void gfree_interfaces(void) +{ + while (local_interfaces) { + struct interface *iface = local_interfaces; + DLIST_REMOVE(local_interfaces, local_interfaces); + ZERO_STRUCTPN(iface); + SAFE_FREE(iface); + } + + SAFE_FREE(probed_ifaces); +} + /**************************************************************************** return True if the list of probed interfaces has changed ****************************************************************************/ diff --git a/source/lib/ldap_escape.c b/source/lib/ldap_escape.c index 26230884341..8907399be4a 100644 --- a/source/lib/ldap_escape.c +++ b/source/lib/ldap_escape.c @@ -89,3 +89,47 @@ char *escape_ldap_string_alloc(const char *s) *p = '\0'; return output; } + +char *escape_rdn_val_string_alloc(const char *s) +{ + char *output, *p; + + /* The maximum size of the escaped string can be twice the actual size */ + output = (char *)SMB_MALLOC(2*strlen(s) + 1); + + if (output == NULL) { + return NULL; + } + + p = output; + + while (*s) + { + switch (*s) + { + case ',': + case '=': + case '+': + case '<': + case '>': + case '#': + case ';': + case '\\': + case '\"': + *p++ = '\\'; + *p++ = *s; + break; + default: + *p = *s; + p++; + } + + s++; + } + + *p = '\0'; + + /* resize the string to the actual final size */ + output = (char *)SMB_REALLOC(output, strlen(output) + 1); + return output; +} diff --git a/source/lib/messages.c b/source/lib/messages.c index e0bf86a46ce..e2c8a6b52fa 100644 --- a/source/lib/messages.c +++ b/source/lib/messages.c @@ -133,6 +133,9 @@ BOOL message_init(void) return False; } + /* Activate the per-hashchain freelist */ + tdb_set_max_dead(tdb, 5); + CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1); message_register(MSG_PING, ping_message, NULL); diff --git a/source/lib/smbldap_util.c b/source/lib/smbldap_util.c index aff4eff6f6d..11b27bf98fb 100644 --- a/source/lib/smbldap_util.c +++ b/source/lib/smbldap_util.c @@ -39,12 +39,21 @@ static NTSTATUS add_new_domain_account_policies(struct smbldap_state *ldap_state const char *policy_attr = NULL; pstring dn; LDAPMod **mods = NULL; + char *escape_domain_name; DEBUG(3,("add_new_domain_account_policies: Adding new account policies for domain\n")); - + + escape_domain_name = escape_rdn_val_string_alloc(domain_name); + if (!escape_domain_name) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - domain_name, lp_ldap_suffix()); + escape_domain_name, lp_ldap_suffix()); + + SAFE_FREE(escape_domain_name); for (i=1; decode_account_policy_name(i) != NULL; i++) { @@ -104,10 +113,20 @@ static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state, LDAPMessage *result = NULL; int num_result; const char **attr_list; + char *escape_domain_name; + + /* escape for filter */ + escape_domain_name = escape_ldap_string_alloc(domain_name); + if (!escape_domain_name) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - domain_name, LDAP_OBJ_DOMINFO); + escape_domain_name, LDAP_OBJ_DOMINFO); + + SAFE_FREE(escape_domain_name); attr_list = get_attr_list( NULL, dominfo_attr_list ); rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result); @@ -129,9 +148,18 @@ static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state, /* Check if we need to add an entry */ DEBUG(3,("add_new_domain_info: Adding new domain\n")); + /* this time escape for DN */ + escape_domain_name = escape_rdn_val_string_alloc(domain_name); + if (!escape_domain_name) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - domain_name, lp_ldap_suffix()); + escape_domain_name, lp_ldap_suffix()); + + SAFE_FREE(escape_domain_name); /* Free original search */ ldap_msgfree(result); @@ -210,11 +238,20 @@ NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state, int rc; const char **attr_list; int count; + char *escape_domain_name; + + escape_domain_name = escape_ldap_string_alloc(domain_name); + if (!escape_domain_name) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))", LDAP_OBJ_DOMINFO, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - domain_name); + escape_domain_name); + + SAFE_FREE(escape_domain_name); DEBUG(2, ("smbldap_search_domain_info: Searching for:[%s]\n", filter)); diff --git a/source/lib/system.c b/source/lib/system.c index 20b31113ecd..eaebc7190f0 100644 --- a/source/lib/system.c +++ b/source/lib/system.c @@ -47,20 +47,35 @@ A wrapper for memalign ********************************************************************/ -void* sys_memalign( size_t align, size_t size ) +void *sys_memalign( size_t align, size_t size ) { -#if defined(HAVE_MEMALIGN) - return memalign( align, size ); -#elif defined(HAVE_POSIX_MEMALIGN) - char *p = NULL; +#if defined(HAVE_POSIX_MEMALIGN) + void *p = NULL; int ret = posix_memalign( &p, align, size ); if ( ret == 0 ) return p; return NULL; +#elif defined(HAVE_MEMALIGN) + return memalign( align, size ); #else - DEBUG(0,("memalign functionalaity not available on this platform!\n")); - return NULL; + /* On *BSD systems memaligns doesn't exist, but memory will + * be aligned on allocations of > pagesize. */ +#if defined(SYSCONF_SC_PAGESIZE) + size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); +#elif defined(HAVE_GETPAGESIZE) + size_t pagesize = (size_t)getpagesize(); +#else + size_t pagesize = (size_t)-1; +#endif + if (pagesize == (size_t)-1) { + DEBUG(0,("memalign functionalaity not available on this platform!\n")); + return NULL; + } + if (size < pagesize) { + size = pagesize; + } + return SMB_MALLOC(size); #endif } diff --git a/source/lib/time.c b/source/lib/time.c index 403fb0594d4..e98f8232abc 100644 --- a/source/lib/time.c +++ b/source/lib/time.c @@ -4,6 +4,7 @@ Copyright (C) Andrew Tridgell 1992-2004 Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Jeremy Allison 2007 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 @@ -36,17 +37,21 @@ #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN) #endif -/** +#define NTTIME_INFINITY (NTTIME)0x8000000000000000LL + +/*************************************************************************** External access to time_t_min and time_t_max. -**/ +****************************************************************************/ + time_t get_time_t_max(void) { return TIME_T_MAX; } -/** -a gettimeofday wrapper -**/ +/*************************************************************************** + A gettimeofday wrapper. +****************************************************************************/ + void GetTimeOfDay(struct timeval *tval) { #ifdef HAVE_GETTIMEOFDAY_TZ @@ -56,14 +61,6 @@ void GetTimeOfDay(struct timeval *tval) #endif } -struct timespec convert_time_t_to_timespec(time_t t) -{ - struct timespec ts; - ts.tv_sec = t; - ts.tv_nsec = 0; - return ts; -} - #if (SIZEOF_LONG == 8) #define TIME_FIXUP_CONSTANT_INT 11644473600L #elif (SIZEOF_LONG_LONG == 8) @@ -111,10 +108,10 @@ void unix_to_nt_time(NTTIME *nt, time_t t) *nt = t2; } +/**************************************************************************** + Check if it's a null unix time. +****************************************************************************/ -/** -check if it's a null unix time -**/ BOOL null_time(time_t t) { return t == 0 || @@ -122,15 +119,26 @@ BOOL null_time(time_t t) t == (time_t)-1; } +/**************************************************************************** + Check if it's a null NTTIME. +****************************************************************************/ -/** -check if it's a null NTTIME -**/ BOOL null_nttime(NTTIME t) { return t == 0 || t == (NTTIME)-1; } +/**************************************************************************** + Check if it's a null timespec. +****************************************************************************/ + +BOOL null_timespec(struct timespec ts) +{ + return ts.tv_sec == 0 || + ts.tv_sec == (time_t)0xFFFFFFFF || + ts.tv_sec == (time_t)-1; +} + /******************************************************************* create a 16 bit dos packed date ********************************************************************/ @@ -547,8 +555,9 @@ NTTIME timeval_to_nttime(const struct timeval *tv) } /******************************************************************* -yield the difference between *A and *B, in seconds, ignoring leap seconds + Yield the difference between *A and *B, in seconds, ignoring leap seconds. ********************************************************************/ + static int tm_diff(struct tm *a, struct tm *b) { int ay = a->tm_year + (1900 - 1); @@ -566,9 +575,10 @@ static int tm_diff(struct tm *a, struct tm *b) int extra_time_offset=0; -/** - return the UTC offset in seconds west of UTC, or 0 if it cannot be determined - */ +/******************************************************************* + Return the UTC offset in seconds west of UTC, or 0 if it cannot be determined. +********************************************************************/ + int get_time_zone(time_t t) { struct tm *tm = gmtime(&t); @@ -778,7 +788,7 @@ void put_long_date(char *p, time_t t) structure. ****************************************************************************/ -time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs) +time_t get_create_time(const SMB_STRUCT_STAT *st,BOOL fake_dirs) { time_t ret, ret1; @@ -800,7 +810,7 @@ time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs) return ret; } -struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) +struct timespec get_create_timespec(const SMB_STRUCT_STAT *st,BOOL fake_dirs) { struct timespec ts; ts.tv_sec = get_create_time(st, fake_dirs); @@ -812,7 +822,7 @@ struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) Get/Set all the possible time fields from a stat struct as a timespec. ****************************************************************************/ -struct timespec get_atimespec(SMB_STRUCT_STAT *pst) +struct timespec get_atimespec(const SMB_STRUCT_STAT *pst) { #if !defined(HAVE_STAT_HIRES_TIMESTAMPS) struct timespec ret; @@ -852,7 +862,7 @@ void set_atimespec(SMB_STRUCT_STAT *pst, struct timespec ts) #endif } -struct timespec get_mtimespec(SMB_STRUCT_STAT *pst) +struct timespec get_mtimespec(const SMB_STRUCT_STAT *pst) { #if !defined(HAVE_STAT_HIRES_TIMESTAMPS) struct timespec ret; @@ -892,7 +902,7 @@ void set_mtimespec(SMB_STRUCT_STAT *pst, struct timespec ts) #endif } -struct timespec get_ctimespec(SMB_STRUCT_STAT *pst) +struct timespec get_ctimespec(const SMB_STRUCT_STAT *pst) { #if !defined(HAVE_STAT_HIRES_TIMESTAMPS) struct timespec ret; @@ -1020,6 +1030,81 @@ time_t convert_timespec_to_time_t(struct timespec ts) return ts.tv_sec; } +struct timespec convert_time_t_to_timespec(time_t t) +{ + struct timespec ts; + ts.tv_sec = t; + ts.tv_nsec = 0; + return ts; +} + +/**************************************************************************** + Convert a normalized timeval to a timespec. +****************************************************************************/ + +struct timespec convert_timeval_to_timespec(const struct timeval tv) +{ + struct timespec ts; + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + return ts; +} + +/**************************************************************************** + Convert a normalized timespec to a timeval. +****************************************************************************/ + +struct timeval convert_timespec_to_timeval(const struct timespec ts) +{ + struct timeval tv; + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; + return tv; +} + +/**************************************************************************** + Return a timespec for the current time +****************************************************************************/ + +struct timespec timespec_current(void) +{ + struct timeval tv; + struct timespec ts; + GetTimeOfDay(&tv); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_sec * 1000; + return ts; +} + +/**************************************************************************** + Return the lesser of two timespecs. +****************************************************************************/ + +struct timespec timespec_min(const struct timespec *ts1, + const struct timespec *ts2) +{ + if (ts1->tv_sec < ts2->tv_sec) return *ts1; + if (ts1->tv_sec > ts2->tv_sec) return *ts2; + if (ts1->tv_nsec < ts2->tv_nsec) return *ts1; + return *ts2; +} + +/**************************************************************************** + compare two timespec structures. + Return -1 if ts1 < ts2 + Return 0 if ts1 == ts2 + Return 1 if ts1 > ts2 +****************************************************************************/ + +int timespec_compare(const struct timespec *ts1, const struct timespec *ts2) +{ + if (ts1->tv_sec > ts2->tv_sec) return 1; + if (ts1->tv_sec < ts2->tv_sec) return -1; + if (ts1->tv_nsec > ts2->tv_nsec) return 1; + if (ts1->tv_nsec < ts2->tv_nsec) return -1; + return 0; +} + /**************************************************************************** Interprets an nt time into a unix struct timespec. Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff @@ -1180,6 +1265,10 @@ time_t nt_time_to_unix_abs(const NTTIME *nt) return (time_t)-1; } + if (*nt == NTTIME_INFINITY) { + return (time_t)-1; + } + /* reverse the time */ /* it's a negative value, turn it to positive */ d=~*nt; @@ -1248,7 +1337,7 @@ void unix_to_nt_time_abs(NTTIME *nt, time_t t) if (t == (time_t)-1) { /* that's what NT uses for infinite */ - *nt = 0x8000000000000000LL; + *nt = NTTIME_INFINITY; return; } @@ -1278,10 +1367,10 @@ BOOL null_mtime(time_t mtime) and asctime fail. ****************************************************************************/ -const char *time_to_asc(const time_t *t) +const char *time_to_asc(const time_t t) { const char *asct; - struct tm *lt = localtime(t); + struct tm *lt = localtime(&t); if (!lt) { return "unknown time"; @@ -1306,7 +1395,7 @@ const char *display_time(NTTIME nttime) if (nttime==0) return "Now"; - if (nttime==0x8000000000000000LL) + if (nttime==NTTIME_INFINITY) return "Never"; high = 65536; @@ -1335,10 +1424,9 @@ BOOL nt_time_is_set(const NTTIME *nt) return False; } - if (*nt == 0x8000000000000000LL) { + if (*nt == NTTIME_INFINITY) { return False; } return True; } - diff --git a/source/lib/util.c b/source/lib/util.c index 67c9c8d37a7..45d3916ebe6 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -200,6 +200,7 @@ void gfree_all( void ) gfree_debugsyms(); gfree_charcnv(); gfree_messages(); + gfree_interfaces(); /* release the talloc null_context memory last */ talloc_disable_null_tracking(); @@ -579,6 +580,13 @@ void dos_clean_name(char *s) /* remove any double slashes */ all_string_sub(s, "\\\\", "\\", 0); + /* Remove leading .\\ characters */ + if(strncmp(s, ".\\", 2) == 0) { + trim_string(s, ".\\", NULL); + if(*s == 0) + pstrcpy(s,".\\"); + } + while ((p = strstr_m(s,"\\..\\")) != NULL) { pstring s1; @@ -593,7 +601,6 @@ void dos_clean_name(char *s) } trim_string(s,NULL,"\\.."); - all_string_sub(s, "\\.\\", "\\", 0); } @@ -631,6 +638,13 @@ void unix_clean_name(char *s) } trim_string(s,NULL,"/.."); + all_string_sub(s, "/./", "/", 0); +} + +void clean_name(char *s) +{ + dos_clean_name(s); + unix_clean_name(s); } /******************************************************************* @@ -913,17 +927,6 @@ void *malloc_(size_t size) } /**************************************************************************** - Internal malloc wrapper. Externally visible. -****************************************************************************/ - -void *memalign_(size_t align, size_t size) -{ -#undef memalign - return memalign(align, size); -#define memalign(align, s) __ERROR_DONT_USE_MEMALIGN_DIRECTLY -} - -/**************************************************************************** Internal calloc wrapper. Not externally visible. ****************************************************************************/ @@ -974,11 +977,7 @@ void *memalign_array(size_t el_size, size_t align, unsigned int count) return NULL; } -#if defined(PARANOID_MALLOC_CHECKER) - return memalign_(align, el_size*count); -#else return sys_memalign(align, el_size*count); -#endif } /**************************************************************************** @@ -2093,6 +2092,9 @@ BOOL is_myname_or_ipaddr(const char *s) /* check for loopback */ + if (strequal(servername, "127.0.0.1")) + return True; + if (strequal(servername, "localhost")) return True; diff --git a/source/libaddns/dnsgss.c b/source/libaddns/dnsgss.c index 798fd4404ee..8324e6761f3 100644 --- a/source/libaddns/dnsgss.c +++ b/source/libaddns/dnsgss.c @@ -252,6 +252,11 @@ DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm, krb5_init_context( &krb_ctx ); krb5_parse_name( krb_ctx, targetname, &host_principal ); + /* don't free the principal until after you call + gss_release_name() or else you'll get a segv + as the krb5_copy_principal() does a structure + copy and not a deep copy. --jerry*/ + input_name.value = &host_principal; input_name.length = sizeof( host_principal ); @@ -267,8 +272,11 @@ DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm, err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname, targ_name, gss_ctx, srv_type ); - + gss_release_name( &minor, &targ_name ); + + /* now we can free the principal */ + krb5_free_principal( krb_ctx, host_principal ); krb5_free_context( krb_ctx ); diff --git a/source/libads/cldap.c b/source/libads/cldap.c index 72018c620d8..3cb98c59c58 100644 --- a/source/libads/cldap.c +++ b/source/libads/cldap.c @@ -187,8 +187,10 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply) { int ret; ASN1_DATA data; - DATA_BLOB blob; - DATA_BLOB os1, os2, os3; + DATA_BLOB blob = data_blob(NULL, 0); + DATA_BLOB os1 = data_blob(NULL, 0); + DATA_BLOB os2 = data_blob(NULL, 0); + DATA_BLOB os3 = data_blob(NULL, 0); int i1; /* half the time of a regular ldap timeout, not less than 3 seconds. */ unsigned int al_secs = MAX(3,lp_ldap_timeout()/2); @@ -238,6 +240,9 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply) if (data.has_error) { data_blob_free(&blob); + data_blob_free(&os1); + data_blob_free(&os2); + data_blob_free(&os3); asn1_free(&data); DEBUG(1,("Failed to parse cldap reply\n")); return -1; diff --git a/source/libads/kerberos_keytab.c b/source/libads/kerberos_keytab.c index ba1a9165674..0ad225fbebb 100644 --- a/source/libads/kerberos_keytab.c +++ b/source/libads/kerberos_keytab.c @@ -55,20 +55,20 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, ret = smb_krb5_parse_name(context, princ_s, &princ); if (ret) { - DEBUG(1,("ads_keytab_add_entry: smb_krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret))); + DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret))); goto out; } /* Seek and delete old keytab entries */ ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret != KRB5_KT_END && ret != ENOENT ) { - DEBUG(3,("ads_keytab_add_entry: Will try to delete old keytab entries\n")); + DEBUG(3,("smb_krb5_kt_add_entry: Will try to delete old keytab entries\n")); while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) { BOOL compare_name_ok = False; ret = smb_krb5_unparse_name(context, kt_entry.principal, &ktprinc); if (ret) { - DEBUG(1,("ads_keytab_add_entry: smb_krb5_unparse_name failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); goto out; } @@ -89,7 +89,7 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, #endif if (!compare_name_ok) { - DEBUG(10,("ads_keytab_add_entry: ignoring keytab entry principal %s, kvno = %d\n", + DEBUG(10,("smb_krb5_kt_add_entry: ignoring keytab entry principal %s, kvno = %d\n", ktprinc, kt_entry.vno)); } @@ -97,39 +97,39 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, if (compare_name_ok) { if (kt_entry.vno == kvno - 1) { - DEBUG(5,("ads_keytab_add_entry: Saving previous (kvno %d) entry for principal: %s.\n", + DEBUG(5,("smb_krb5_kt_add_entry: Saving previous (kvno %d) entry for principal: %s.\n", kvno - 1, princ_s)); } else { - DEBUG(5,("ads_keytab_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n", + DEBUG(5,("smb_krb5_kt_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n", princ_s, kt_entry.vno)); ret = krb5_kt_end_seq_get(context, keytab, &cursor); ZERO_STRUCT(cursor); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get() failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_end_seq_get() failed (%s)\n", error_message(ret))); goto out; } ret = krb5_kt_remove_entry(context, keytab, &kt_entry); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_remove_entry failed (%s)\n", error_message(ret))); goto out; } - DEBUG(5,("ads_keytab_add_entry: removed old entry for principal: %s (kvno %d).\n", + DEBUG(5,("smb_krb5_kt_add_entry: removed old entry for principal: %s (kvno %d).\n", princ_s, kt_entry.vno)); ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_start_seq failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_start_seq failed (%s)\n", error_message(ret))); goto out; } ret = smb_krb5_kt_free_entry(context, &kt_entry); ZERO_STRUCT(kt_entry); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_remove_entry failed (%s)\n", error_message(ret))); goto out; } @@ -141,7 +141,7 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, ret = smb_krb5_kt_free_entry(context, &kt_entry); ZERO_STRUCT(kt_entry); if (ret) { - DEBUG(1,("ads_keytab_add_entry: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret))); + DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret))); goto out; } } @@ -149,7 +149,7 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, ret = krb5_kt_end_seq_get(context, keytab, &cursor); ZERO_STRUCT(cursor); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get failed (%s)\n",error_message(ret))); + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_end_seq_get failed (%s)\n",error_message(ret))); goto out; } } @@ -180,13 +180,13 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, kt_entry.principal = princ; kt_entry.vno = kvno; - DEBUG(3,("ads_keytab_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n", + DEBUG(3,("smb_krb5_kt_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n", princ_s, enctypes[i], kt_entry.vno)); ret = krb5_kt_add_entry(context, keytab, &kt_entry); krb5_free_keyblock_contents(context, keyp); ZERO_STRUCT(kt_entry); if (ret) { - DEBUG(1,("ads_keytab_add_entry: adding entry to keytab failed (%s)\n", error_message(ret))); + DEBUG(1,("smb_krb5_kt_add_entry: adding entry to keytab failed (%s)\n", error_message(ret))); goto out; } } diff --git a/source/libads/kerberos_verify.c b/source/libads/kerberos_verify.c index 2c114b1240e..0ec03ef4bf2 100644 --- a/source/libads/kerberos_verify.c +++ b/source/libads/kerberos_verify.c @@ -7,6 +7,7 @@ Copyright (C) Guenther Deschner 2003, 2005 Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 + Copyright (C) Jeremy Allison 2007 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 @@ -37,9 +38,12 @@ const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int ); ads_keytab_add_entry function for details. ***********************************************************************************/ -static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, - const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock **keyblock) +static BOOL ads_keytab_verify_ticket(krb5_context context, + krb5_auth_context auth_context, + const DATA_BLOB *ticket, + krb5_ticket **pp_tkt, + krb5_keyblock **keyblock, + krb5_error_code *perr) { krb5_error_code ret = 0; BOOL auth_ok = False; @@ -51,6 +55,11 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut fstring my_name, my_fqdn; int i; int number_matched_principals = 0; + krb5_data packet; + + *pp_tkt = NULL; + *keyblock = NULL; + *perr = 0; /* Generate the list of principal names which we expect * clients might want to use for authenticating to the file @@ -103,11 +112,11 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut } number_matched_principals++; - p_packet->length = ticket->length; - p_packet->data = (char *)ticket->data; + packet.length = ticket->length; + packet.data = (char *)ticket->data; *pp_tkt = NULL; - ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, p_packet, + ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet, kt_entry.principal, keytab, NULL, pp_tkt, keyblock); @@ -125,7 +134,8 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut * entries - Guenther */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || - ret == KRB5KRB_AP_ERR_TKT_EXPIRED) { + ret == KRB5KRB_AP_ERR_TKT_EXPIRED || + ret == KRB5KRB_AP_ERR_SKEW) { break; } } else { @@ -184,6 +194,7 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut if (keytab) { krb5_kt_close(context, keytab); } + *perr = ret; return auth_ok; } @@ -191,32 +202,40 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut Try to verify a ticket using the secrets.tdb. ***********************************************************************************/ -static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context, - krb5_principal host_princ, - const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock **keyblock) +static krb5_error_code ads_secrets_verify_ticket(krb5_context context, + krb5_auth_context auth_context, + krb5_principal host_princ, + const DATA_BLOB *ticket, + krb5_ticket **pp_tkt, + krb5_keyblock **keyblock, + krb5_error_code *perr) { krb5_error_code ret = 0; BOOL auth_ok = False; char *password_s = NULL; krb5_data password; krb5_enctype enctypes[4] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, 0, 0 }; + krb5_data packet; int i; + *pp_tkt = NULL; + *keyblock = NULL; + *perr = 0; + #if defined(ENCTYPE_ARCFOUR_HMAC) enctypes[2] = ENCTYPE_ARCFOUR_HMAC; #endif - ZERO_STRUCTP(keyblock); - if (!secrets_init()) { DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n")); + *perr = KRB5_CONFIG_CANTOPEN; return False; } password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (!password_s) { DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n")); + *perr = KRB5_LIBOS_CANTREADPWD; return False; } @@ -225,14 +244,15 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ - p_packet->length = ticket->length; - p_packet->data = (char *)ticket->data; + packet.length = ticket->length; + packet.data = (char *)ticket->data; /* We need to setup a auth context with each possible encoding type in turn. */ for (i=0;enctypes[i];i++) { krb5_keyblock *key = NULL; if (!(key = SMB_MALLOC_P(krb5_keyblock))) { + ret = ENOMEM; goto out; } @@ -243,7 +263,7 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au krb5_auth_con_setuseruserkey(context, auth_context, key); - if (!(ret = krb5_rd_req(context, &auth_context, p_packet, + if (!(ret = krb5_rd_req(context, &auth_context, &packet, NULL, NULL, NULL, pp_tkt))) { DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", @@ -260,7 +280,8 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au /* successfully decrypted but ticket is just not valid at the moment */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || - ret == KRB5KRB_AP_ERR_TKT_EXPIRED) { + ret == KRB5KRB_AP_ERR_TKT_EXPIRED || + ret == KRB5KRB_AP_ERR_SKEW) { break; } @@ -270,7 +291,7 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au out: SAFE_FREE(password_s); - + *perr = ret; return auth_ok; } @@ -280,9 +301,11 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au ***********************************************************************************/ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, - const char *realm, time_t time_offset, - const DATA_BLOB *ticket, - char **principal, PAC_DATA **pac_data, + const char *realm, + time_t time_offset, + const DATA_BLOB *ticket, + char **principal, + PAC_DATA **pac_data, DATA_BLOB *ap_rep, DATA_BLOB *session_key) { @@ -296,20 +319,22 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, krb5_rcache rcache = NULL; krb5_keyblock *keyblock = NULL; time_t authtime; - int ret; - + krb5_error_code ret = 0; + krb5_principal host_princ = NULL; krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; - BOOL got_replay_mutex = False; - BOOL auth_ok = False; + BOOL got_replay_mutex = False; BOOL got_auth_data = False; ZERO_STRUCT(packet); ZERO_STRUCT(auth_data); - ZERO_STRUCTP(ap_rep); - ZERO_STRUCTP(session_key); + + *principal = NULL; + *pac_data = NULL; + *ap_rep = data_blob(NULL,0); + *session_key = data_blob(NULL,0); initialize_krb5_error_table(); ret = krb5_init_context(&context); @@ -339,6 +364,10 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } asprintf(&host_princ_s, "%s$", global_myname()); + if (!host_princ_s) { + goto out; + } + strlower_m(host_princ_s); ret = smb_krb5_parse_name(context, host_princ_s, &host_princ); if (ret) { @@ -353,6 +382,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, if (!grab_server_mutex("replay cache mutex")) { DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n")); + ret = KRB5_CC_IO; goto out; } @@ -375,11 +405,11 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } if (lp_use_kerberos_keytab()) { - auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &packet, &tkt, &keyblock); + auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &tkt, &keyblock, &ret); } if (!auth_ok) { auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, - ticket, &packet, &tkt, &keyblock); + ticket, &tkt, &keyblock, &ret); } release_server_mutex(); @@ -395,6 +425,15 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, if (!auth_ok) { DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", error_message(ret))); + /* Try map the error return in case it's something like + * a clock skew error. + */ + sret = krb5_to_nt_status(ret); + if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) { + sret = NT_STATUS_LOGON_FAILURE; + } + DEBUG(10,("ads_verify_ticket: returning error %s\n", + nt_errstr(sret) )); goto out; } @@ -409,8 +448,10 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } *ap_rep = data_blob(packet.data, packet.length); - SAFE_FREE(packet.data); - packet.length = 0; + if (packet.data) { + kerberos_free_data_contents(context, &packet); + ZERO_STRUCT(packet); + } get_krb5_smb_session_key(context, auth_context, session_key, True); dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); diff --git a/source/libads/krb5_errs.c b/source/libads/krb5_errs.c index 89cfc2d1439..c153bee96e6 100644 --- a/source/libads/krb5_errs.c +++ b/source/libads/krb5_errs.c @@ -59,6 +59,8 @@ static const struct { {KRB5_CC_NOTFOUND, NT_STATUS_NO_SUCH_FILE}, {KRB5_FCC_NOFILE, NT_STATUS_NO_SUCH_FILE}, {KRB5KDC_ERR_NONE, NT_STATUS_OK}, + {KRB5_RC_MALLOC, NT_STATUS_NO_MEMORY}, + {ENOMEM, NT_STATUS_NO_MEMORY}, {0, NT_STATUS_OK} }; diff --git a/source/libads/ldap.c b/source/libads/ldap.c index dfc68fdc2b1..1d08a01a263 100644 --- a/source/libads/ldap.c +++ b/source/libads/ldap.c @@ -1635,6 +1635,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, char *samAccountName, *controlstr; TALLOC_CTX *ctx; ADS_MODLIST mods; + char *machine_escaped = NULL; char *new_dn; const char *objectClass[] = {"top", "person", "organizationalPerson", "user", "computer", NULL}; @@ -1647,8 +1648,13 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, return ADS_ERROR(LDAP_NO_MEMORY); ret = ADS_ERROR(LDAP_NO_MEMORY); - - new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_name, org_unit); + + machine_escaped = escape_rdn_val_string_alloc(machine_name); + if (!machine_escaped) { + goto done; + } + + new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_escaped, org_unit); samAccountName = talloc_asprintf(ctx, "%s$", machine_name); if ( !new_dn || !samAccountName ) { @@ -1675,6 +1681,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, ret = ads_gen_add(ads, new_dn, mods); done: + SAFE_FREE(machine_escaped); ads_msgfree(ads, res); talloc_destroy(ctx); diff --git a/source/libads/ldap_user.c b/source/libads/ldap_user.c index 66d94d29d3a..afbbc0b421a 100644 --- a/source/libads/ldap_user.c +++ b/source/libads/ldap_user.c @@ -50,6 +50,7 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user, ADS_MODLIST mods; ADS_STATUS status; const char *upn, *new_dn, *name, *controlstr; + char *name_escaped = NULL; const char *objectClass[] = {"top", "person", "organizationalPerson", "user", NULL}; @@ -63,7 +64,9 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user, if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->config.realm))) goto done; - if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", name, container, + if (!(name_escaped = escape_rdn_val_string_alloc(name))) + goto done; + if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", name_escaped, container, ads->config.bind_path))) goto done; if (!(controlstr = talloc_asprintf(ctx, "%u", (UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE)))) @@ -81,6 +84,7 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user, status = ads_gen_add(ads, new_dn, mods); done: + SAFE_FREE(name_escaped); talloc_destroy(ctx); return status; } @@ -92,6 +96,7 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group, ADS_MODLIST mods; ADS_STATUS status; char *new_dn; + char *name_escaped = NULL; const char *objectClass[] = {"top", "group", NULL}; if (!(ctx = talloc_init("ads_add_group_acct"))) @@ -99,7 +104,9 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group, status = ADS_ERROR(LDAP_NO_MEMORY); - if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", group, container, + if (!(name_escaped = escape_rdn_val_string_alloc(group))) + goto done; + if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", name_escaped, container, ads->config.bind_path))) goto done; if (!(mods = ads_init_mods(ctx))) @@ -114,6 +121,7 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group, status = ads_gen_add(ads, new_dn, mods); done: + SAFE_FREE(name_escaped); talloc_destroy(ctx); return status; } diff --git a/source/libads/sasl.c b/source/libads/sasl.c index 812f3961f19..013985a1215 100644 --- a/source/libads/sasl.c +++ b/source/libads/sasl.c @@ -311,9 +311,9 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) int gss_rc, rc; uint8 *p; uint32 max_msg_size = 0; - char *sname; + char *sname = NULL; ADS_STATUS status; - krb5_principal principal; + krb5_principal principal = NULL; krb5_context ctx = NULL; krb5_enctype enc_types[] = { #ifdef ENCTYPE_ARCFOUR_HMAC @@ -331,25 +331,40 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) initialize_krb5_error_table(); status = ADS_ERROR_KRB5(krb5_init_context(&ctx)); if (!ADS_ERR_OK(status)) { + SAFE_FREE(sname); return status; } status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types)); if (!ADS_ERR_OK(status)) { + SAFE_FREE(sname); + krb5_free_context(ctx); return status; } status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal)); if (!ADS_ERR_OK(status)) { + SAFE_FREE(sname); + krb5_free_context(ctx); return status; } - free(sname); - krb5_free_context(ctx); - input_name.value = &principal; input_name.length = sizeof(principal); gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name); + + /* + * The MIT libraries have a *HORRIBLE* bug - input_value.value needs + * to point to the *address* of the krb5_principal, and the gss libraries + * to a shallow copy of the krb5_principal pointer - so we need to keep + * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* ! + * Just one more way in which MIT engineers screwed me over.... JRA. + */ + + SAFE_FREE(sname); + if (gss_rc) { + krb5_free_principal(ctx, principal); + krb5_free_context(ctx); return ADS_ERROR_GSS(gss_rc, minor_status); } @@ -407,8 +422,6 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) if (gss_rc == 0) break; } - gss_release_name(&minor_status, &serv_name); - gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token, (int *)&conf_state,NULL); if (gss_rc) { @@ -463,6 +476,11 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) gss_release_buffer(&minor_status, &input_token); failed: + + gss_release_name(&minor_status, &serv_name); + krb5_free_principal(ctx, principal); + krb5_free_context(ctx); + if(scred) ber_bvfree(scred); return status; diff --git a/source/libads/smb_krb5_locator.c b/source/libads/smb_krb5_locator.c new file mode 100644 index 00000000000..be14a126974 --- /dev/null +++ b/source/libads/smb_krb5_locator.c @@ -0,0 +1,386 @@ +/* + Unix SMB/CIFS implementation. + kerberos locator plugin + Copyright (C) Guenther Deschner 2007 + + 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" + +#if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H) + +#include <krb5/locate_plugin.h> + +static const char *get_service_from_locate_service_type(enum locate_service_type svc) +{ + switch (svc) { + case locate_service_kdc: + case locate_service_master_kdc: + return "88"; + case locate_service_kadmin: + case locate_service_krb524: + /* not supported */ + return NULL; + case locate_service_kpasswd: + return "464"; + default: + break; + } + return NULL; + +} + +static const char *locate_service_type_name(enum locate_service_type svc) +{ + switch (svc) { + case locate_service_kdc: + return "locate_service_kdc"; + case locate_service_master_kdc: + return "locate_service_master_kdc"; + case locate_service_kadmin: + return "locate_service_kadmin"; + case locate_service_krb524: + return "locate_service_krb524"; + case locate_service_kpasswd: + return "locate_service_kpasswd"; + default: + break; + } + return NULL; +} + +static const char *socktype_name(int socktype) +{ + switch (socktype) { + case SOCK_STREAM: + return "SOCK_STREAM"; + case SOCK_DGRAM: + return "SOCK_DGRAM"; + default: + break; + } + return "unknown"; +} + +static const char *family_name(int family) +{ + switch (family) { + case AF_UNSPEC: + return "AF_UNSPEC"; + case AF_INET: + return "AF_INET"; + case AF_INET6: + return "AF_INET6"; + default: + break; + } + return "unknown"; +} + +/** + * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones + * + * @param svc + * @param realm string + * @param socktype integer + * @param family integer + * + * @return integer. + */ + +static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc, + const char *realm, + int socktype, + int family) +{ + if (!realm || strlen(realm) == 0) { + return EINVAL; + } + + switch (svc) { + case locate_service_kdc: + case locate_service_master_kdc: + case locate_service_kpasswd: + break; + case locate_service_kadmin: + case locate_service_krb524: +#ifdef KRB5_PLUGIN_NO_HANDLE + return KRB5_PLUGIN_NO_HANDLE; +#else + return KRB5_KDC_UNREACH; /* Heimdal */ +#endif + default: + return EINVAL; + } + + switch (family) { + case AF_UNSPEC: + case AF_INET: + break; + case AF_INET6: /* not yet */ +#ifdef KRB5_PLUGIN_NO_HANDLE + return KRB5_PLUGIN_NO_HANDLE; +#else + return KRB5_KDC_UNREACH; /* Heimdal */ +#endif + default: + return EINVAL; + } + + switch (socktype) { + case SOCK_STREAM: + case SOCK_DGRAM: + case 0: /* Heimdal uses that */ + break; + default: + return EINVAL; + } + + return 0; +} + +/** + * Try to get addrinfo for a given host and call the krb5 callback + * + * @param name string + * @param service string + * @param in struct addrinfo hint + * @param cbfunc krb5 callback function + * @param cbdata void pointer cbdata + * + * @return krb5_error_code. + */ + +static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name, + const char *service, + struct addrinfo *in, + int (*cbfunc)(void *, int, struct sockaddr *), + void *cbdata) +{ + struct addrinfo *out; + int ret; + int count = 3; + + while (count) { + + ret = getaddrinfo(name, service, in, &out); + if (ret == 0) { + break; + } + + if (ret == EAI_AGAIN) { + count--; + continue; + } + + DEBUG(10,("smb_krb5_locator_lookup: got ret: %s (%d)\n", + gai_strerror(ret), ret)); +#ifdef KRB5_PLUGIN_NO_HANDLE + return KRB5_PLUGIN_NO_HANDLE; +#else + return KRB5_KDC_UNREACH; /* Heimdal */ +#endif + } + + ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr); + if (ret) { + DEBUG(10,("smb_krb5_locator_lookup: failed to call callback: %s (%d)\n", + error_message(ret), ret)); + } + + freeaddrinfo(out); + + return ret; +} + +/** + * PUBLIC INTERFACE: locate init + * + * @param context krb5_context + * @param privata_data pointer to private data pointer + * + * @return krb5_error_code. + */ + +krb5_error_code smb_krb5_locator_init(krb5_context context, + void **private_data) +{ + setup_logging("smb_krb5_locator", True); + load_case_tables(); + lp_load(dyn_CONFIGFILE,True,False,False,True); + + DEBUG(10,("smb_krb5_locator_init: called\n")); + + return 0; +} + +/** + * PUBLIC INTERFACE: close locate + * + * @param private_data pointer to private data + * + * @return void. + */ + +void smb_krb5_locator_close(void *private_data) +{ + DEBUG(10,("smb_krb5_locator_close: called\n")); + + /* gfree_all(); */ +} + +/** + * PUBLIC INTERFACE: locate lookup + * + * @param private_data pointer to private data + * @param svc enum locate_service_type. + * @param realm string + * @param socktype integer + * @param family integer + * @param cbfunc callback function to send back entries + * @param cbdata void pointer to cbdata + * + * @return krb5_error_code. + */ + +krb5_error_code smb_krb5_locator_lookup(void *private_data, + enum locate_service_type svc, + const char *realm, + int socktype, + int family, + int (*cbfunc)(void *, int, struct sockaddr *), + void *cbdata) +{ + NTSTATUS status; + krb5_error_code ret; + char *sitename = NULL; + struct ip_service *ip_list; + int count = 0; + struct addrinfo aihints; + char *saf_name = NULL; + int i; + + DEBUG(10,("smb_krb5_locator_lookup: called for\n")); + DEBUGADD(10,("\tsvc: %s (%d), realm: %s\n", + locate_service_type_name(svc), svc, realm)); + DEBUGADD(10,("\tsocktype: %s (%d), family: %s (%d)\n", + socktype_name(socktype), socktype, + family_name(family), family)); + + ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype, family); + if (ret) { + DEBUG(10,("smb_krb5_locator_lookup: returning ret: %s (%d)\n", + error_message(ret), ret)); + return ret; + } + + /* first try to fetch from SAF cache */ + + saf_name = saf_fetch(realm); + if (!saf_name || strlen(saf_name) == 0) { + DEBUG(10,("smb_krb5_locator_lookup: no SAF name stored for %s\n", + realm)); + goto find_kdc; + } + + DEBUG(10,("smb_krb5_locator_lookup: got %s for %s from SAF cache\n", + saf_name, realm)); + + ZERO_STRUCT(aihints); + + aihints.ai_family = family; + aihints.ai_socktype = socktype; + + ret = smb_krb5_locator_call_cbfunc(saf_name, + get_service_from_locate_service_type(svc), + &aihints, + cbfunc, cbdata); + if (ret) { + return ret; + } + + return 0; + + find_kdc: + + /* now try to find via site-aware DNS SRV query */ + + sitename = sitename_fetch(realm); + status = get_kdc_list(realm, sitename, &ip_list, &count); + + /* if we didn't found any KDCs on our site go to the main list */ + + if (NT_STATUS_IS_OK(status) && sitename && (count == 0)) { + SAFE_FREE(ip_list); + SAFE_FREE(sitename); + status = get_kdc_list(realm, NULL, &ip_list, &count); + } + + SAFE_FREE(sitename); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("smb_krb5_locator_lookup: got %s (%s)\n", + nt_errstr(status), + error_message(nt_status_to_krb5(status)))); +#ifdef KRB5_PLUGIN_NO_HANDLE + return KRB5_PLUGIN_NO_HANDLE; +#else + return KRB5_KDC_UNREACH; /* Heimdal */ +#endif + } + + for (i=0; i<count; i++) { + + const char *host = NULL; + const char *port = NULL; + + ZERO_STRUCT(aihints); + + aihints.ai_family = family; + aihints.ai_socktype = socktype; + + host = inet_ntoa(ip_list[i].ip); + port = get_service_from_locate_service_type(svc); + + ret = smb_krb5_locator_call_cbfunc(host, + port, + &aihints, + cbfunc, cbdata); + if (ret) { + /* got error */ + break; + } + } + + SAFE_FREE(ip_list); + + return ret; +} + +#ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H +#define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */ +#else +#define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */ +#endif + +const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = { + 0, /* version */ + smb_krb5_locator_init, + smb_krb5_locator_close, + smb_krb5_locator_lookup, +}; + +#endif diff --git a/source/librpc/ndr/libndr.h b/source/librpc/ndr/libndr.h index 32dd0ef6c59..faa7c56455d 100644 --- a/source/librpc/ndr/libndr.h +++ b/source/librpc/ndr/libndr.h @@ -223,7 +223,7 @@ enum ndr_compression_alg { } \ } while(0) -#define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, ndr->offset+(n))) +#define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, n)) #define NDR_PUSH_ALIGN(ndr, n) do { \ if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \ diff --git a/source/librpc/ndr/ndr.c b/source/librpc/ndr/ndr.c index f6a132c1861..4f0599e5c03 100644 --- a/source/librpc/ndr/ndr.c +++ b/source/librpc/ndr/ndr.c @@ -160,10 +160,18 @@ DATA_BLOB ndr_push_blob(struct ndr_push *ndr) /* - expand the available space in the buffer to 'size' + expand the available space in the buffer to ndr->offset + extra_size */ -NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32_t size) +NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size) { + uint32_t size = extra_size + ndr->offset; + + if (size < ndr->offset) { + /* extra_size overflowed the offset */ + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u", + size); + } + if (ndr->alloc_size > size) { return NT_STATUS_OK; } diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c index e2213c1fcde..0f09747dbf1 100644 --- a/source/libsmb/cliconnect.c +++ b/source/libsmb/cliconnect.c @@ -693,8 +693,6 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n")); nt_status = NT_STATUS_UNSUCCESSFUL; } else { - data_blob_free(&msg1); - blob = cli_session_setup_blob_receive(cli); nt_status = cli_nt_error(cli); @@ -706,6 +704,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use } } } + data_blob_free(&msg1); } if (!blob.length) { @@ -736,6 +735,8 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use turn++; } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)); + data_blob_free(&blob_in); + if (NT_STATUS_IS_OK(nt_status)) { DATA_BLOB key = data_blob(ntlmssp_state->session_key.data, diff --git a/source/libsmb/clidfs.c b/source/libsmb/clidfs.c index 916e4cefc6e..4009b98b418 100644 --- a/source/libsmb/clidfs.c +++ b/source/libsmb/clidfs.c @@ -3,6 +3,7 @@ client connect/disconnect routines Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Gerald (Jerry) Carter 2004 + Copyright (C) Jeremy Allison 2007 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 @@ -21,6 +22,16 @@ #include "includes.h" +/******************************************************************** + Important point. + + DFS paths are *always* of the form \server\share\<pathname> (the \ characters + are not C escaped here). + + - but if we're using POSIX paths then <pathname> may contain + '/' separators, not '\\' separators. So cope with '\\' or '/' + as a separator when looking at the pathname part.... JRA. +********************************************************************/ struct client_connection { struct client_connection *prev, *next; @@ -194,14 +205,14 @@ static void cli_cm_set_mntpoint( struct cli_state *c, const char *mnt ) if ( p ) { pstrcpy( p->mount, mnt ); - dos_clean_name( p->mount ); + clean_name(p->mount); } } /**************************************************************************** ****************************************************************************/ -const char * cli_cm_get_mntpoint( struct cli_state *c ) +const char *cli_cm_get_mntpoint( struct cli_state *c ) { struct client_connection *p; int i; @@ -221,8 +232,9 @@ const char * cli_cm_get_mntpoint( struct cli_state *c ) Add a new connection to the list ********************************************************************/ -static struct cli_state* cli_cm_connect( const char *server, const char *share, - BOOL show_hdr ) +static struct cli_state *cli_cm_connect( const char *server, + const char *share, + BOOL show_hdr) { struct client_connection *node; @@ -247,7 +259,7 @@ static struct cli_state* cli_cm_connect( const char *server, const char *share, Return a connection to a server. ********************************************************************/ -static struct cli_state* cli_cm_find( const char *server, const char *share ) +static struct cli_state *cli_cm_find( const char *server, const char *share ) { struct client_connection *p; @@ -264,7 +276,9 @@ static struct cli_state* cli_cm_find( const char *server, const char *share ) global variable as a side-effect (but only if the connection is successful). ****************************************************************************/ -struct cli_state* cli_cm_open( const char *server, const char *share, BOOL show_hdr ) +struct cli_state *cli_cm_open(const char *server, + const char *share, + BOOL show_hdr) { struct cli_state *c; @@ -272,8 +286,9 @@ struct cli_state* cli_cm_open( const char *server, const char *share, BOOL show_ c = cli_cm_find( server, share ); - if ( !c ) - c = cli_cm_connect( server, share, show_hdr ); + if ( !c ) { + c = cli_cm_connect(server, share, show_hdr); + } return c; } @@ -295,7 +310,6 @@ void cli_cm_shutdown( void ) } connections = NULL; - return; } @@ -354,110 +368,104 @@ void cli_cm_set_dest_ip(struct in_addr ip ) have_ip = True; } -/******************************************************************** - split a dfs path into the server and share name components -********************************************************************/ +/********************************************************************** + split a dfs path into the server, share name, and extrapath components +**********************************************************************/ -static void split_dfs_path( const char *nodepath, fstring server, fstring share ) +static void split_dfs_path( const char *nodepath, fstring server, fstring share, pstring extrapath ) { - char *p; + char *p, *q; pstring path; pstrcpy( path, nodepath ); - if ( path[0] != '\\' ) + if ( path[0] != '\\' ) { return; + } - p = strrchr_m( path, '\\' ); - - if ( !p ) + p = strchr_m( path + 1, '\\' ); + if ( !p ) { return; + } *p = '\0'; p++; + /* Look for any extra/deep path */ + q = strchr_m(p, '\\'); + if (q != NULL) { + *q = '\0'; + q++; + pstrcpy( extrapath, q ); + } else { + pstrcpy( extrapath, '\0' ); + } + fstrcpy( share, p ); fstrcpy( server, &path[1] ); } /**************************************************************************** - return the original path truncated at the first wildcard character - (also strips trailing \'s). Trust the caller to provide a NULL + Return the original path truncated at the directory component before + the first wildcard character. Trust the caller to provide a NULL terminated string ****************************************************************************/ -static void clean_path( pstring clean, const char *path ) +static void clean_path(const char *path, pstring path_out) { - int len; - char *p; - pstring newpath; - - pstrcpy( newpath, path ); - p = newpath; - - while ( p ) { - /* first check for '*' */ + size_t len; + char *p1, *p2, *p; - p = strrchr_m( newpath, '*' ); - if ( p ) { - *p = '\0'; - p = newpath; - continue; + /* No absolute paths. */ + while (IS_DIRECTORY_SEP(*path)) { + path++; + } + + pstrcpy(path_out, path); + + p1 = strchr_m(path_out, '*'); + p2 = strchr_m(path_out, '?'); + + if (p1 || p2) { + if (p1 && p2) { + p = MIN(p1,p2); + } else if (!p1) { + p = p2; + } else { + p = p1; } - - /* first check for '?' */ - - p = strrchr_m( newpath, '?' ); - if ( p ) { + *p = '\0'; + + /* Now go back to the start of this component. */ + p1 = strrchr_m(path_out, '/'); + p2 = strrchr_m(path_out, '\\'); + p = MAX(p1,p2); + if (p) { *p = '\0'; - p = newpath; } } - - /* strip a trailing backslash */ - - len = strlen( newpath ); - if ( (len > 0) && (newpath[len-1] == '\\') ) - newpath[len-1] = '\0'; - - pstrcpy( clean, newpath ); + + /* Strip any trailing separator */ + + len = strlen(path_out); + if ( (len > 0) && IS_DIRECTORY_SEP(path_out[len-1])) { + path_out[len-1] = '\0'; + } } /**************************************************************************** ****************************************************************************/ -BOOL cli_dfs_make_full_path( pstring path, const char *server, const char *share, - const char *dir ) +static void cli_dfs_make_full_path( struct cli_state *cli, + const char *dir, + pstring path_out) { - pstring servicename; - char *sharename; - const char *directory; - - - /* make a copy so we don't modify the global string 'service' */ - - pstrcpy(servicename, share); - sharename = servicename; - - if (*sharename == '\\') { - - server = sharename+2; - sharename = strchr_m(server,'\\'); - - if (!sharename) - return False; - - *sharename = 0; - sharename++; + /* Ensure the extrapath doesn't start with a separator. */ + while (IS_DIRECTORY_SEP(*dir)) { + dir++; } - directory = dir; - if ( *directory == '\\' ) - directory++; - - pstr_sprintf( path, "\\%s\\%s\\%s", server, sharename, directory ); - - return True; + pstr_sprintf( path_out, "\\%s\\%s\\%s", cli->desthost, cli->share, dir); } /******************************************************************** @@ -483,9 +491,11 @@ static BOOL cli_dfs_check_error( struct cli_state *cli, NTSTATUS status ) get the dfs referral link ********************************************************************/ -BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path, - CLIENT_DFS_REFERRAL**refs, size_t *num_refs, - uint16 *consumed) +BOOL cli_dfs_get_referral( struct cli_state *cli, + const char *path, + CLIENT_DFS_REFERRAL**refs, + size_t *num_refs, + uint16 *consumed) { unsigned int data_len = 0; unsigned int param_len = 0; @@ -529,10 +539,9 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path, uint16 ref_size; int i; uint16 node_offset; - - + referrals = SMB_XMALLOC_ARRAY( CLIENT_DFS_REFERRAL, num_referrals ); - + /* start at the referrals array */ p = rdata+8; @@ -554,7 +563,6 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path, p += ref_size; } - } *num_refs = num_referrals; @@ -566,115 +574,167 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path, return True; } + /******************************************************************** ********************************************************************/ -BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const char *path, - struct cli_state **targetcli, pstring targetpath ) +BOOL cli_resolve_path( const char *mountpt, + struct cli_state *rootcli, + const char *path, + struct cli_state **targetcli, + pstring targetpath) { CLIENT_DFS_REFERRAL *refs = NULL; size_t num_refs; uint16 consumed; struct cli_state *cli_ipc; - pstring fullpath, cleanpath; + pstring dfs_path, cleanpath, extrapath; int pathlen; fstring server, share; struct cli_state *newcli; pstring newpath; pstring newmount; - char *ppath; + char *ppath, *temppath = NULL; SMB_STRUCT_STAT sbuf; uint32 attributes; - if ( !rootcli || !path || !targetcli ) + if ( !rootcli || !path || !targetcli ) { return False; + } - *targetcli = NULL; - - /* send a trans2_query_path_info to check for a referral */ - - clean_path( cleanpath, path ); - cli_dfs_make_full_path( fullpath, rootcli->desthost, rootcli->share, cleanpath ); + /* Don't do anything if this is not a DFS root. */ - /* don't bother continuing if this is not a dfs root */ - - if ( !rootcli->dfsroot || cli_qpathinfo_basic( rootcli, cleanpath, &sbuf, &attributes ) ) { + if ( !rootcli->dfsroot) { *targetcli = rootcli; pstrcpy( targetpath, path ); return True; } - /* special case where client asked for a path that does not exist */ + *targetcli = NULL; + + /* Send a trans2_query_path_info to check for a referral. */ + + clean_path(path, cleanpath); + cli_dfs_make_full_path(rootcli, cleanpath, dfs_path ); + + if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes ) ) { + /* This is an ordinary path, just return it. */ + *targetcli = rootcli; + pstrcpy( targetpath, path ); + goto done; + } + + /* Special case where client asked for a path that does not exist */ if ( cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND) ) { *targetcli = rootcli; pstrcpy( targetpath, path ); - return True; + goto done; } - /* we got an error, check for DFS referral */ - - if ( !cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED) ) + /* We got an error, check for DFS referral. */ + + if ( !cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED)) { return False; + } - /* check for the referral */ + /* Check for the referral. */ - if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) ) + if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) ) { return False; + } - if ( !cli_dfs_get_referral(cli_ipc, fullpath, &refs, &num_refs, &consumed) - || !num_refs ) - { + if ( !cli_dfs_get_referral(cli_ipc, dfs_path, &refs, &num_refs, &consumed) + || !num_refs ) { return False; } - /* just store the first referral for now - Make sure to recreate the original string including any wildcards */ + /* Just store the first referral for now. */ + + split_dfs_path( refs[0].dfspath, server, share, extrapath ); + SAFE_FREE(refs); + + /* Make sure to recreate the original string including any wildcards. */ - cli_dfs_make_full_path( fullpath, rootcli->desthost, rootcli->share, path ); - pathlen = strlen( fullpath )*2; + cli_dfs_make_full_path( rootcli, path, dfs_path); + pathlen = strlen( dfs_path )*2; consumed = MIN(pathlen, consumed ); - pstrcpy( targetpath, &fullpath[consumed/2] ); + pstrcpy( targetpath, &dfs_path[consumed/2] ); + dfs_path[consumed/2] = '\0'; - split_dfs_path( refs[0].dfspath, server, share ); - SAFE_FREE( refs ); - - /* open the connection to the target path */ + /* + * targetpath is now the unconsumed part of the path. + * dfs_path is now the consumed part of the path (in \server\share\path format). + */ + + /* Open the connection to the target server & share */ if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) { - d_printf("Unable to follow dfs referral [//%s/%s]\n", + d_printf("Unable to follow dfs referral [\\%s\\%s]\n", server, share ); - return False; } + if (strlen(extrapath) > 0) { + string_append(&temppath, extrapath); + string_append(&temppath, targetpath); + pstrcpy( targetpath, temppath ); + } + /* parse out the consumed mount path */ /* trim off the \server\share\ */ - fullpath[consumed/2] = '\0'; - dos_clean_name( fullpath ); - if ((ppath = strchr_m( fullpath, '\\' )) == NULL) + ppath = dfs_path; + + if (*ppath != '\\') { + d_printf("cli_resolve_path: dfs_path (%s) not in correct format.\n", + dfs_path ); return False; - if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) + } + + ppath++; /* Now pointing at start of server name. */ + + if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) { return False; - if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) + } + + ppath++; /* Now pointing at start of share name. */ + + if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) { return False; - ppath++; - + } + + ppath++; /* Now pointing at path component. */ + pstr_sprintf( newmount, "%s\\%s", mountpt, ppath ); + cli_cm_set_mntpoint( *targetcli, newmount ); - /* check for another dfs referral, note that we are not - checking for loops here */ + /* Check for another dfs referral, note that we are not + checking for loops here. */ - if ( !strequal( targetpath, "\\" ) ) { + if ( !strequal( targetpath, "\\" ) && !strequal( targetpath, "/")) { if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) { + /* + * When cli_resolve_path returns true here it's always + * returning the complete path in newpath, so we're done + * here. + */ *targetcli = newcli; pstrcpy( targetpath, newpath ); + return True; } } + done: + + /* If returning True ensure we return a dfs root full path. */ + if ( (*targetcli)->dfsroot ) { + pstrcpy(dfs_path, targetpath ); + cli_dfs_make_full_path( *targetcli, dfs_path, targetpath); + } + return True; } @@ -690,6 +750,7 @@ BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename, pstring fullpath; BOOL res; uint16 cnum; + pstring newextrapath; if ( !cli || !sharename ) return False; @@ -698,8 +759,9 @@ BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename, /* special case. never check for a referral on the IPC$ share */ - if ( strequal( sharename, "IPC$" ) ) + if ( strequal( sharename, "IPC$" ) ) { return False; + } /* send a trans2_query_path_info to check for a referral */ @@ -719,13 +781,13 @@ BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename, } cli->cnum = cnum; - + if (!res || !num_refs ) { SAFE_FREE( refs ); return False; } - split_dfs_path( refs[0].dfspath, newserver, newshare ); + split_dfs_path( refs[0].dfspath, newserver, newshare, newextrapath ); /* check that this is not a self-referral */ diff --git a/source/libsmb/clifile.c b/source/libsmb/clifile.c index 2fe9eb17259..ce2081a81e1 100644 --- a/source/libsmb/clifile.c +++ b/source/libsmb/clifile.c @@ -1775,3 +1775,200 @@ BOOL cli_get_ea_list_fnum(struct cli_state *cli, int fnum, return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list); } + +/**************************************************************************** + Convert open "flags" arg to uint32 on wire. +****************************************************************************/ + +static uint32 open_flags_to_wire(int flags) +{ + int open_mode = flags & O_ACCMODE; + uint32 ret = 0; + + switch (open_mode) { + case O_WRONLY: + ret |= SMB_O_WRONLY; + break; + case O_RDWR: + ret |= SMB_O_RDWR; + break; + default: + case O_RDONLY: + ret |= SMB_O_RDONLY; + break; + } + + if (flags & O_CREAT) { + ret |= SMB_O_CREAT; + } + if (flags & O_EXCL) { + ret |= SMB_O_EXCL; + } + if (flags & O_TRUNC) { + ret |= SMB_O_TRUNC; + } +#if defined(O_SYNC) + if (flags & O_SYNC) { + ret |= SMB_O_SYNC; + } +#endif /* O_SYNC */ + if (flags & O_APPEND) { + ret |= SMB_O_APPEND; + } +#if defined(O_DIRECT) + if (flags & O_DIRECT) { + ret |= SMB_O_DIRECT; + } +#endif +#if defined(O_DIRECTORY) + if (flags & O_DIRECTORY) { + ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY); + ret |= SMB_O_DIRECTORY; + } +#endif + return ret; +} + +/**************************************************************************** + Open a file - POSIX semantics. Returns fnum. Doesn't request oplock. +****************************************************************************/ + +static int cli_posix_open_internal(struct cli_state *cli, const char *fname, int flags, mode_t mode, BOOL is_dir) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_SETPATHINFO; + char param[sizeof(pstring)+6]; + char data[18]; + char *rparam=NULL, *rdata=NULL; + char *p; + int fnum = -1; + uint32 wire_flags = open_flags_to_wire(flags); + + memset(param, 0, sizeof(param)); + SSVAL(param,0, SMB_POSIX_PATH_OPEN); + p = ¶m[6]; + + p += clistr_push(cli, p, fname, sizeof(param)-6, STR_TERMINATE); + param_len = PTR_DIFF(p, param); + + if (is_dir) { + wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY); + wire_flags |= SMB_O_DIRECTORY; + } + + p = data; + SIVAL(p,0,0); /* No oplock. */ + SIVAL(p,4,wire_flags); + SIVAL(p,8,unix_perms_to_wire(mode)); + SIVAL(p,12,0); /* Top bits of perms currently undefined. */ + SSVAL(p,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */ + + data_len = 18; + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + (char *)&data, data_len, cli->max_xmit /* data, length, max */ + )) { + return -1; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return -1; + } + + fnum = SVAL(rdata,2); + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + + return fnum; +} + +/**************************************************************************** + open - POSIX semantics. +****************************************************************************/ + +int cli_posix_open(struct cli_state *cli, const char *fname, int flags, mode_t mode) +{ + return cli_posix_open_internal(cli, fname, flags, mode, False); +} + +/**************************************************************************** + mkdir - POSIX semantics. +****************************************************************************/ + +int cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode) +{ + return (cli_posix_open_internal(cli, fname, O_CREAT, mode, True) == -1) ? -1 : 0; +} + +/**************************************************************************** + unlink or rmdir - POSIX semantics. +****************************************************************************/ + +static BOOL cli_posix_unlink_internal(struct cli_state *cli, const char *fname, BOOL is_dir) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_SETPATHINFO; + char param[sizeof(pstring)+6]; + char data[2]; + char *rparam=NULL, *rdata=NULL; + char *p; + + memset(param, 0, sizeof(param)); + SSVAL(param,0, SMB_POSIX_PATH_UNLINK); + p = ¶m[6]; + + p += clistr_push(cli, p, fname, sizeof(param)-6, STR_TERMINATE); + param_len = PTR_DIFF(p, param); + + SSVAL(data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET : + SMB_POSIX_UNLINK_FILE_TARGET); + data_len = 2; + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + (char *)&data, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + + return True; +} + +/**************************************************************************** + unlink - POSIX semantics. +****************************************************************************/ + +BOOL cli_posix_unlink(struct cli_state *cli, const char *fname) +{ + return cli_posix_unlink_internal(cli, fname, False); +} + +/**************************************************************************** + rmdir - POSIX semantics. +****************************************************************************/ + +int cli_posix_rmdir(struct cli_state *cli, const char *fname) +{ + return cli_posix_unlink_internal(cli, fname, True); +} diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c index f06a19b345c..5018e146cad 100644 --- a/source/libsmb/clikrb5.c +++ b/source/libsmb/clikrb5.c @@ -75,6 +75,7 @@ static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context, krb5_error_code ret; char *utf8_name; + *principal = NULL; if (push_utf8_allocate(&utf8_name, name) == (size_t)-1) { return ENOMEM; } @@ -97,6 +98,7 @@ static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context, krb5_error_code ret; char *utf8_name; + *unix_name = NULL; ret = krb5_unparse_name(context, principal, &utf8_name); if (ret) { return ret; @@ -1415,6 +1417,43 @@ done: } #endif + krb5_error_code smb_krb5_mk_error(krb5_context context, + krb5_error_code error_code, + const krb5_principal server, + krb5_data *reply) +{ +#ifdef HAVE_SHORT_KRB5_MK_ERROR_INTERFACE /* MIT */ + /* + * The MIT interface is *terrible*. + * We have to construct this ourselves... + */ + krb5_error e; + + memset(&e, 0, sizeof(e)); + krb5_us_timeofday(context, &e.stime, &e.susec); + e.server = server; +#if defined(krb5_err_base) + e.error = error_code - krb5_err_base; +#elif defined(ERROR_TABLE_BASE_krb5) + e.error = error_code - ERROR_TABLE_BASE_krb5; +#else + e.error = error_code; /* Almost certainly wrong, but what can we do... ? */ +#endif + + return krb5_mk_error(context, &e, reply); +#else /* Heimdal. */ + return krb5_mk_error(context, + error_code, + NULL, + NULL, /* e_data */ + NULL, + server, + NULL, + NULL, + reply); +#endif +} + #else /* HAVE_KRB5 */ /* this saves a few linking headaches */ int cli_krb5_get_ticket(const char *principal, time_t time_offset, diff --git a/source/libsmb/clilist.c b/source/libsmb/clilist.c index 22cb5930c26..3e76cd47754 100644 --- a/source/libsmb/clilist.c +++ b/source/libsmb/clilist.c @@ -44,6 +44,7 @@ static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,f *p_resume_key = 0; } memcpy(finfo,&def_finfo,sizeof(*finfo)); + finfo->cli = cli; switch (level) { case 1: /* OS/2 understands this */ @@ -185,13 +186,7 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, /* NT uses 260, OS/2 uses 2. Both accept 1. */ info_level = (cli->capabilities&CAP_NT_SMBS)?260:1; - /* when getting a directory listing from a 2k dfs root share, - we have to include the full path (\server\share\mask) here */ - - if ( cli->dfsroot ) - pstr_sprintf( mask, "\\%s\\%s\\%s", cli->desthost, cli->share, Mask ); - else - pstrcpy(mask,Mask); + pstrcpy(mask,Mask); while (ff_eos == 0) { loop_count++; @@ -377,6 +372,7 @@ static int interpret_short_filename(struct cli_state *cli, char *p,file_info *fi *finfo = def_finfo; + finfo->cli = cli; finfo->mode = CVAL(p,21); /* this date is converted to GMT by make_unix_date */ diff --git a/source/libsmb/cliquota.c b/source/libsmb/cliquota.c index 25c36c214fc..5627d28bb5d 100644 --- a/source/libsmb/cliquota.c +++ b/source/libsmb/cliquota.c @@ -323,11 +323,13 @@ BOOL cli_list_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) { DEBUG(0,("talloc_zero() failed\n")); + talloc_destroy(mem_ctx); return (-1); } if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) { DEBUG(0,("talloc_zero() failed\n")); + talloc_destroy(mem_ctx); return (-1); } diff --git a/source/libsmb/clirap.c b/source/libsmb/clirap.c index 61cdd79f36b..05dc36e91c3 100644 --- a/source/libsmb/clirap.c +++ b/source/libsmb/clirap.c @@ -21,10 +21,10 @@ #include "includes.h" - /**************************************************************************** -Call a remote api on an arbitrary pipe. takes param, data and setup buffers. + Call a remote api on an arbitrary pipe. takes param, data and setup buffers. ****************************************************************************/ + BOOL cli_api_pipe(struct cli_state *cli, const char *pipe_name, uint16 *setup, uint32 setup_count, uint32 max_setup_count, char *params, uint32 param_count, uint32 max_param_count, @@ -32,28 +32,29 @@ BOOL cli_api_pipe(struct cli_state *cli, const char *pipe_name, char **rparam, uint32 *rparam_count, char **rdata, uint32 *rdata_count) { - cli_send_trans(cli, SMBtrans, + cli_send_trans(cli, SMBtrans, pipe_name, 0,0, /* fid, flags */ setup, setup_count, max_setup_count, params, param_count, max_param_count, data, data_count, max_data_count); - return (cli_receive_trans(cli, SMBtrans, + return (cli_receive_trans(cli, SMBtrans, rparam, (unsigned int *)rparam_count, rdata, (unsigned int *)rdata_count)); } /**************************************************************************** -call a remote api + Call a remote api ****************************************************************************/ + BOOL cli_api(struct cli_state *cli, char *param, int prcnt, int mprcnt, char *data, int drcnt, int mdrcnt, char **rparam, unsigned int *rprcnt, char **rdata, unsigned int *rdrcnt) { - cli_send_trans(cli,SMBtrans, + cli_send_trans(cli,SMBtrans, PIPE_LANMAN, /* Name */ 0,0, /* fid, flags */ NULL,0,0, /* Setup, length, max */ @@ -61,15 +62,15 @@ BOOL cli_api(struct cli_state *cli, data, drcnt, mdrcnt /* Data, length, max */ ); - return (cli_receive_trans(cli,SMBtrans, + return (cli_receive_trans(cli,SMBtrans, rparam, rprcnt, rdata, rdrcnt)); } - /**************************************************************************** -perform a NetWkstaUserLogon + Perform a NetWkstaUserLogon. ****************************************************************************/ + BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation) { char *rparam = NULL; @@ -129,8 +130,9 @@ BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation) } /**************************************************************************** -call a NetShareEnum - try and browse available connections on a host + Call a NetShareEnum - try and browse available connections on a host. ****************************************************************************/ + int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state) { char *rparam = NULL; @@ -196,14 +198,14 @@ int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, co return count; } - /**************************************************************************** -call a NetServerEnum for the specified workgroup and servertype mask. This -function then calls the specified callback function for each name returned. + Call a NetServerEnum for the specified workgroup and servertype mask. This + function then calls the specified callback function for each name returned. -The callback function takes 4 arguments: the machine name, the server type, -the comment and a state pointer. + The callback function takes 4 arguments: the machine name, the server type, + the comment and a state pointer. ****************************************************************************/ + BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, void (*fn)(const char *, uint32, const char *, void *), void *state) @@ -286,99 +288,99 @@ BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, return(count > 0); } - - /**************************************************************************** -Send a SamOEMChangePassword command + Send a SamOEMChangePassword command. ****************************************************************************/ + BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password, const char *old_password) { - pstring param; - unsigned char data[532]; - char *p = param; - unsigned char old_pw_hash[16]; - unsigned char new_pw_hash[16]; - unsigned int data_len; - unsigned int param_len = 0; - char *rparam = NULL; - char *rdata = NULL; - unsigned int rprcnt, rdrcnt; - - if (strlen(user) >= sizeof(fstring)-1) { - DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user)); - return False; - } - - SSVAL(p,0,214); /* SamOEMChangePassword command. */ - p += 2; - pstrcpy_base(p, "zsT", param); - p = skip_string(p,1); - pstrcpy_base(p, "B516B16", param); - p = skip_string(p,1); - pstrcpy_base(p,user, param); - p = skip_string(p,1); - SSVAL(p,0,532); - p += 2; - - param_len = PTR_DIFF(p,param); - - /* - * Get the Lanman hash of the old password, we - * use this as the key to make_oem_passwd_hash(). - */ - E_deshash(old_password, old_pw_hash); - - encode_pw_buffer(data, new_password, STR_ASCII); + pstring param; + unsigned char data[532]; + char *p = param; + unsigned char old_pw_hash[16]; + unsigned char new_pw_hash[16]; + unsigned int data_len; + unsigned int param_len = 0; + char *rparam = NULL; + char *rdata = NULL; + unsigned int rprcnt, rdrcnt; + + if (strlen(user) >= sizeof(fstring)-1) { + DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user)); + return False; + } + + SSVAL(p,0,214); /* SamOEMChangePassword command. */ + p += 2; + pstrcpy_base(p, "zsT", param); + p = skip_string(p,1); + pstrcpy_base(p, "B516B16", param); + p = skip_string(p,1); + pstrcpy_base(p,user, param); + p = skip_string(p,1); + SSVAL(p,0,532); + p += 2; + + param_len = PTR_DIFF(p,param); + + /* + * Get the Lanman hash of the old password, we + * use this as the key to make_oem_passwd_hash(). + */ + E_deshash(old_password, old_pw_hash); + + encode_pw_buffer(data, new_password, STR_ASCII); #ifdef DEBUG_PASSWORD - DEBUG(100,("make_oem_passwd_hash\n")); - dump_data(100, (char *)data, 516); + DEBUG(100,("make_oem_passwd_hash\n")); + dump_data(100, (char *)data, 516); #endif - SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516); + SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516); - /* - * Now place the old password hash in the data. - */ - E_deshash(new_password, new_pw_hash); + /* + * Now place the old password hash in the data. + */ + E_deshash(new_password, new_pw_hash); - E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]); + E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]); - data_len = 532; + data_len = 532; - if (cli_send_trans(cli,SMBtrans, + if (cli_send_trans(cli,SMBtrans, PIPE_LANMAN, /* name */ 0,0, /* fid, flags */ NULL,0,0, /* setup, length, max */ param,param_len,2, /* param, length, max */ (char *)data,data_len,0 /* data, length, max */ ) == False) { - DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n", - user )); - return False; - } + DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n", + user )); + return False; + } - if (!cli_receive_trans(cli,SMBtrans, + if (!cli_receive_trans(cli,SMBtrans, &rparam, &rprcnt, &rdata, &rdrcnt)) { - DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n", - user )); - return False; - } + DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n", + user )); + return False; + } - if (rparam) - cli->rap_error = SVAL(rparam,0); + if (rparam) { + cli->rap_error = SVAL(rparam,0); + } - SAFE_FREE(rparam); - SAFE_FREE(rdata); + SAFE_FREE(rparam); + SAFE_FREE(rdata); - return (cli->rap_error == 0); + return (cli->rap_error == 0); } - /**************************************************************************** -send a qpathinfo call + Send a qpathinfo call. ****************************************************************************/ + BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, time_t *change_time, time_t *access_time, @@ -458,10 +460,10 @@ BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, return True; } - /**************************************************************************** -send a setpathinfo call + Send a setpathinfo call. ****************************************************************************/ + BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, time_t create_time, time_t access_time, @@ -556,9 +558,8 @@ BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, return True; } - /**************************************************************************** -send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level + Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level. ****************************************************************************/ BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, @@ -631,10 +632,10 @@ BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, return True; } - /**************************************************************************** -send a qfileinfo QUERY_FILE_NAME_INFO call + Send a qfileinfo QUERY_FILE_NAME_INFO call. ****************************************************************************/ + BOOL cli_qfilename(struct cli_state *cli, int fnum, pstring name) { @@ -674,10 +675,10 @@ BOOL cli_qfilename(struct cli_state *cli, int fnum, return True; } - /**************************************************************************** -send a qfileinfo call + Send a qfileinfo call. ****************************************************************************/ + BOOL cli_qfileinfo(struct cli_state *cli, int fnum, uint16 *mode, SMB_OFF_T *size, struct timespec *create_time, @@ -749,10 +750,10 @@ BOOL cli_qfileinfo(struct cli_state *cli, int fnum, return True; } - /**************************************************************************** -send a qpathinfo BASIC_INFO call + Send a qpathinfo BASIC_INFO call. ****************************************************************************/ + BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf, uint32 *attributes ) { @@ -765,18 +766,12 @@ BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name, pstring path; int len; - /* send full paths to dfs root shares */ - - if ( cli->dfsroot ) - pstr_sprintf(path, "\\%s\\%s\\%s", cli->desthost, cli->share, name ); - else - pstrcpy( path, name ); - + pstrcpy( path, name ); /* cleanup */ len = strlen( path ); - if ( path[len] == '\\' ) - path[len] = '\0'; + if ( path[len-1] == '\\' || path[len-1] == '/') + path[len-1] = '\0'; p = param; memset(p, 0, 6); @@ -820,7 +815,7 @@ BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name, } /**************************************************************************** -send a qfileinfo call + Send a qfileinfo call. ****************************************************************************/ BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen) @@ -875,11 +870,10 @@ BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutd return True; } - - /**************************************************************************** -send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call + Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call. ****************************************************************************/ + NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name) { unsigned int data_len = 0; diff --git a/source/libsmb/doserr.c b/source/libsmb/doserr.c index 8628db3abc9..414c2d49168 100644 --- a/source/libsmb/doserr.c +++ b/source/libsmb/doserr.c @@ -68,6 +68,7 @@ werror_code_struct dos_errs[] = { "WERR_DFS_CANT_CREATE_JUNCT", WERR_DFS_CANT_CREATE_JUNCT }, { "WERR_MACHINE_LOCKED", WERR_MACHINE_LOCKED }, { "WERR_NO_LOGON_SERVERS", WERR_NO_LOGON_SERVERS }, + { "WERR_LOGON_FAILURE", WERR_LOGON_FAILURE }, { "WERR_NO_SUCH_DOMAIN", WERR_NO_SUCH_DOMAIN }, { "WERR_INVALID_SECURITY_DESCRIPTOR", WERR_INVALID_SECURITY_DESCRIPTOR }, { "WERR_INVALID_OWNER", WERR_INVALID_OWNER }, @@ -83,8 +84,9 @@ werror_code_struct dos_errs[] = }; /***************************************************************************** - returns a DOS error message. not amazingly helpful, but better than a number. + Returns a DOS error message. not amazingly helpful, but better than a number. *****************************************************************************/ + const char *dos_errstr(WERROR werror) { static pstring msg; diff --git a/source/libsmb/errormap.c b/source/libsmb/errormap.c index 6745c0e23a3..cb5e8311cad 100644 --- a/source/libsmb/errormap.c +++ b/source/libsmb/errormap.c @@ -1511,7 +1511,6 @@ const struct unix_error_map unix_dos_nt_errmap[] = { { EACCES, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED }, { ENOENT, ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND }, { ENOTDIR, ERRDOS, ERRbadpath, NT_STATUS_NOT_A_DIRECTORY }, - { ENAMETOOLONG, ERRDOS, 206, NT_STATUS_OBJECT_NAME_INVALID }, { EIO, ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR }, { EBADF, ERRSRV, ERRsrverror, NT_STATUS_INVALID_HANDLE }, { EINVAL, ERRSRV, ERRsrverror, NT_STATUS_INVALID_HANDLE }, @@ -1534,6 +1533,9 @@ const struct unix_error_map unix_dos_nt_errmap[] = { #ifdef EROFS { EROFS, ERRHRD, ERRnowrite, NT_STATUS_ACCESS_DENIED }, #endif +#ifdef ENAMETOOLONG + { ENAMETOOLONG, ERRDOS, 206, NT_STATUS_OBJECT_NAME_INVALID }, +#endif #ifdef EFBIG { EFBIG, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL }, #endif diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c index 6a154aa68e2..7fbf5a10c54 100644 --- a/source/libsmb/libsmbclient.c +++ b/source/libsmb/libsmbclient.c @@ -1116,13 +1116,6 @@ smbc_open_ctx(SMBCCTX *context, } /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ - if ( targetcli->dfsroot ) - { - pstring temppath; - pstrcpy(temppath, targetpath); - cli_dfs_make_full_path( targetpath, targetcli->desthost, targetcli->share, temppath); - } - if ((fd = cli_open(targetcli, targetpath, flags, context->internal->_share_mode)) < 0) { @@ -1519,14 +1512,6 @@ smbc_getatr(SMBCCTX * context, return False; } - if ( targetcli->dfsroot ) - { - pstring temppath; - pstrcpy(temppath, targetpath); - cli_dfs_make_full_path(targetpath, targetcli->desthost, - targetcli->share, temppath); - } - if (!srv->no_pathinfo2 && cli_qpathinfo2(targetcli, targetpath, create_time_ts, diff --git a/source/locking/brlock.c b/source/locking/brlock.c index 872ed2bbeaf..76a4039d823 100644 --- a/source/locking/brlock.c +++ b/source/locking/brlock.c @@ -273,6 +273,9 @@ void brl_init(int read_only) lock_path("brlock.tdb"))); return; } + + /* Activate the per-hashchain freelist */ + tdb_set_max_dead(tdb, 5); } /**************************************************************************** diff --git a/source/locking/locking.c b/source/locking/locking.c index ffac43aff59..37e6dbc4e54 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -222,6 +222,12 @@ struct byte_range_lock *do_lock(files_struct *fsp, lock_flav, blocking_lock); + /* blocking ie. pending, locks also count here, + * as this is an efficiency counter to avoid checking + * the lock db. on close. JRA. */ + + fsp->current_lock_count++; + return br_lck; } @@ -268,6 +274,9 @@ NTSTATUS do_unlock(files_struct *fsp, return NT_STATUS_RANGE_NOT_LOCKED; } + SMB_ASSERT(fsp->current_lock_count > 0); + fsp->current_lock_count--; + return NT_STATUS_OK; } @@ -315,6 +324,9 @@ NTSTATUS do_lock_cancel(files_struct *fsp, return NT_STATUS_DOS(ERRDOS, ERRcancelviolation); } + SMB_ASSERT(fsp->current_lock_count > 0); + fsp->current_lock_count--; + return NT_STATUS_OK; } @@ -330,6 +342,14 @@ void locking_close_file(files_struct *fsp) return; } + /* If we have not outstanding locks or pending + * locks then we don't need to look in the lock db. + */ + + if (fsp->current_lock_count == 0) { + return; + } + br_lck = brl_get_locks(NULL,fsp); if (br_lck) { @@ -363,6 +383,9 @@ BOOL locking_init(int read_only) return False; } + /* Activate the per-hashchain freelist */ + tdb_set_max_dead(tdb, 5); + if (!posix_locking_init(read_only)) return False; @@ -858,15 +881,29 @@ BOOL rename_share_filename(struct share_mode_lock *lck, return True; } -BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode) +static int pull_delete_on_close_flag(TDB_DATA key, TDB_DATA dbuf, + void *private_data) { - BOOL result; - struct share_mode_lock *lck = get_share_mode_lock(NULL, dev, inode, NULL, NULL); - if (!lck) { - return False; + BOOL *result = (BOOL *)private_data; + struct locking_data *data; + + if (dbuf.dsize < sizeof(struct locking_data)) { + smb_panic("PANIC: parse_share_modes: buffer too short.\n"); } - result = lck->delete_on_close; - TALLOC_FREE(lck); + + data = (struct locking_data *)dbuf.dptr; + + *result = data->u.s.delete_on_close; + return 0; +} + +BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode) +{ + TDB_DATA key = locking_key(dev, inode); + BOOL result = False; + + tdb_parse_record(tdb, key, pull_delete_on_close_flag, + (void *)&result); return result; } diff --git a/source/modules/nfs4_acls.c b/source/modules/nfs4_acls.c index 91ebba1f588..dd452408579 100644 --- a/source/modules/nfs4_acls.c +++ b/source/modules/nfs4_acls.c @@ -604,31 +604,33 @@ BOOL smb_set_nt_acl_nfs4(files_struct *fsp, if (smbacl4_GetFileOwner(fsp, &sbuf)) return False; - /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */ - if (!unpack_nt_owners(SNUM(fsp->conn), &newUID, &newGID, security_info_sent, psd)) - { - DEBUG(8, ("unpack_nt_owners failed")); - return False; - } - if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) || - ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) { - need_chown = True; - } - if (need_chown) { - if ((newUID == (uid_t)-1 || newUID == current_user.ut.uid)) { - if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) { - DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n", - fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, strerror(errno) )); - return False; + if (params.do_chown) { + /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */ + if (!unpack_nt_owners(SNUM(fsp->conn), &newUID, &newGID, security_info_sent, psd)) + { + DEBUG(8, ("unpack_nt_owners failed")); + return False; + } + if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) || + ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) { + need_chown = True; + } + if (need_chown) { + if ((newUID == (uid_t)-1 || newUID == current_user.ut.uid)) { + if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) { + DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n", + fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, strerror(errno) )); + return False; + } + DEBUG(10,("chown %s, %u, %u succeeded.\n", + fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID)); + if (smbacl4_GetFileOwner(fsp, &sbuf)) + return False; + need_chown = False; + } else { /* chown is needed, but _after_ changing acl */ + sbuf.st_uid = newUID; /* OWNER@ in case of e_special */ + sbuf.st_gid = newGID; /* GROUP@ in case of e_special */ } - DEBUG(10,("chown %s, %u, %u succeeded.\n", - fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID)); - if (smbacl4_GetFileOwner(fsp, &sbuf)) - return False; - need_chown = False; - } else { /* chown is needed, but _after_ changing acl */ - sbuf.st_uid = newUID; /* OWNER@ in case of e_special */ - sbuf.st_gid = newGID; /* GROUP@ in case of e_special */ } } diff --git a/source/modules/vfs_cap.c b/source/modules/vfs_cap.c index e058c9660c7..f89e149d0eb 100644 --- a/source/modules/vfs_cap.c +++ b/source/modules/vfs_cap.c @@ -131,11 +131,11 @@ static int cap_chdir(vfs_handle_struct *handle, const char *path) return SMB_VFS_NEXT_CHDIR(handle, cappath); } -static int cap_utime(vfs_handle_struct *handle, const char *path, struct utimbuf *times) +static int cap_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2]) { pstring cappath; capencode(cappath, path); - return SMB_VFS_NEXT_UTIME(handle, cappath, times); + return SMB_VFS_NEXT_NTIMES(handle, cappath, ts); } @@ -327,7 +327,7 @@ static vfs_op_tuple cap_op_tuples[] = { {SMB_VFS_OP(cap_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(cap_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(cap_chdir), SMB_VFS_OP_CHDIR, SMB_VFS_LAYER_TRANSPARENT}, - {SMB_VFS_OP(cap_utime), SMB_VFS_OP_UTIME, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(cap_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(cap_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(cap_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(cap_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT}, diff --git a/source/modules/vfs_catia.c b/source/modules/vfs_catia.c index 478dab6cbed..fe1ce830f7b 100644 --- a/source/modules/vfs_catia.c +++ b/source/modules/vfs_catia.c @@ -184,10 +184,10 @@ static char *catia_getwd(vfs_handle_struct *handle, char *buf) return SMB_VFS_NEXT_GETWD(handle, buf); } -static int catia_utime(vfs_handle_struct *handle, - const char *path, struct utimbuf *times) +static int catia_ntimes(vfs_handle_struct *handle, + const char *path, const struct timespec ts[2]) { - return SMB_VFS_NEXT_UTIME(handle, path, times); + return SMB_VFS_NEXT_NTIMES(handle, path, ts); } static BOOL catia_symlink(vfs_handle_struct *handle, @@ -278,7 +278,7 @@ SMB_VFS_LAYER_TRANSPARENT}, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(catia_getwd), SMB_VFS_OP_GETWD, SMB_VFS_LAYER_TRANSPARENT}, - {SMB_VFS_OP(catia_utime), SMB_VFS_OP_UTIME, + {SMB_VFS_OP(catia_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(catia_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT}, diff --git a/source/modules/vfs_default.c b/source/modules/vfs_default.c index bd7bea5258a..4febc064d94 100644 --- a/source/modules/vfs_default.c +++ b/source/modules/vfs_default.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. Wrap disk only vfs functions to sidestep dodgy compilers. Copyright (C) Tim Potter 1998 + Copyright (C) Jeremy Allison 2007 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 @@ -612,13 +613,35 @@ static char *vfswrap_getwd(vfs_handle_struct *handle, char *path) return result; } -static int vfswrap_utime(vfs_handle_struct *handle, const char *path, struct utimbuf *times) +/********************************************************************* + nsec timestamp resolution call. Convert down to whatever the underlying + system will support. +**********************************************************************/ + +static int vfswrap_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2]) { int result; - START_PROFILE(syscall_utime); - result = utime(path, times); - END_PROFILE(syscall_utime); + START_PROFILE(syscall_ntimes); +#if defined(HAVE_UTIMES) + { + struct timeval tv[2]; + tv[0] = convert_timespec_to_timeval(ts[0]); + tv[1] = convert_timespec_to_timeval(ts[1]); + result = utimes(path, tv); + } +#elif defined(HAVE_UTIME) + { + struct utimebuf times; + times.actime = convert_timespec_to_time_t(ts[0]); + times.modtime = convert_timespec_to_time_t(ts[1]); + result = utime(path, times); + } +#else + errno = ENOSYS; + result = -1; +#endif + END_PROFILE(syscall_ntimes); return result; } @@ -786,7 +809,7 @@ static BOOL vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, int fd, int leasetype) { - int result; + int result = -1; START_PROFILE(syscall_linux_setlease); @@ -796,7 +819,8 @@ static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, return -1; result = linux_setlease(fd, leasetype); - +#else + errno = ENOSYS; #endif END_PROFILE(syscall_linux_setlease); return result; @@ -879,6 +903,12 @@ static NTSTATUS vfswrap_notify_watch(vfs_handle_struct *vfs_handle, return NT_STATUS_OK; } +static int vfswrap_chflags(vfs_handle_struct *handle, const char *path, int flags) +{ + errno = ENOSYS; + return -1; +} + static size_t vfswrap_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info, SEC_DESC **ppdesc) { size_t result; @@ -1238,7 +1268,7 @@ static vfs_op_tuple vfs_default_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_getwd), SMB_VFS_OP_GETWD, SMB_VFS_LAYER_OPAQUE}, - {SMB_VFS_OP(vfswrap_utime), SMB_VFS_OP_UTIME, + {SMB_VFS_OP(vfswrap_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_ftruncate), SMB_VFS_OP_FTRUNCATE, SMB_VFS_LAYER_OPAQUE}, @@ -1262,6 +1292,8 @@ static vfs_op_tuple vfs_default_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_notify_watch), SMB_VFS_OP_NOTIFY_WATCH, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_chflags), SMB_VFS_OP_CHFLAGS, + SMB_VFS_LAYER_OPAQUE}, /* NT ACL operations. */ diff --git a/source/modules/vfs_full_audit.c b/source/modules/vfs_full_audit.c index 6036e49fc15..62530fb09ce 100644 --- a/source/modules/vfs_full_audit.c +++ b/source/modules/vfs_full_audit.c @@ -151,8 +151,8 @@ static int smb_full_audit_chdir(vfs_handle_struct *handle, const char *path); static char *smb_full_audit_getwd(vfs_handle_struct *handle, char *path); -static int smb_full_audit_utime(vfs_handle_struct *handle, - const char *path, struct utimbuf *times); +static int smb_full_audit_ntimes(vfs_handle_struct *handle, + const char *path, const struct timespec ts[2]); static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len); static BOOL smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, @@ -174,6 +174,15 @@ static int smb_full_audit_mknod(vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev); static char *smb_full_audit_realpath(vfs_handle_struct *handle, const char *path, char *resolved_path); +static NTSTATUS smb_full_audit_notify_watch(struct vfs_handle_struct *handle, + struct sys_notify_context *ctx, + struct notify_entry *e, + void (*callback)(struct sys_notify_context *ctx, + void *private_data, + struct notify_event *ev), + void *private_data, void *handle_p); +static int smb_full_audit_chflags(vfs_handle_struct *handle, + const char *path, uint flags); static size_t smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info, SEC_DESC **ppdesc); @@ -375,7 +384,7 @@ static vfs_op_tuple audit_op_tuples[] = { SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_getwd), SMB_VFS_OP_GETWD, SMB_VFS_LAYER_LOGGER}, - {SMB_VFS_OP(smb_full_audit_utime), SMB_VFS_OP_UTIME, + {SMB_VFS_OP(smb_full_audit_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_ftruncate), SMB_VFS_OP_FTRUNCATE, SMB_VFS_LAYER_LOGGER}, @@ -397,6 +406,10 @@ static vfs_op_tuple audit_op_tuples[] = { SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_realpath), SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_LOGGER}, + {SMB_VFS_OP(smb_full_audit_notify_watch),SMB_VFS_OP_NOTIFY_WATCH, + SMB_VFS_LAYER_LOGGER}, + {SMB_VFS_OP(smb_full_audit_chflags), SMB_VFS_OP_CHFLAGS, + SMB_VFS_LAYER_LOGGER}, /* NT ACL operations. */ @@ -549,7 +562,7 @@ static struct { { SMB_VFS_OP_FCHOWN, "fchown" }, { SMB_VFS_OP_CHDIR, "chdir" }, { SMB_VFS_OP_GETWD, "getwd" }, - { SMB_VFS_OP_UTIME, "utime" }, + { SMB_VFS_OP_NTIMES, "ntimes" }, { SMB_VFS_OP_FTRUNCATE, "ftruncate" }, { SMB_VFS_OP_LOCK, "lock" }, { SMB_VFS_OP_KERNEL_FLOCK, "kernel_flock" }, @@ -560,6 +573,8 @@ static struct { { SMB_VFS_OP_LINK, "link" }, { SMB_VFS_OP_MKNOD, "mknod" }, { SMB_VFS_OP_REALPATH, "realpath" }, + { SMB_VFS_OP_NOTIFY_WATCH, "notify_watch" }, + { SMB_VFS_OP_CHFLAGS, "chflags" }, { SMB_VFS_OP_FGET_NT_ACL, "fget_nt_acl" }, { SMB_VFS_OP_GET_NT_ACL, "get_nt_acl" }, { SMB_VFS_OP_FSET_NT_ACL, "fset_nt_acl" }, @@ -1267,14 +1282,14 @@ static char *smb_full_audit_getwd(vfs_handle_struct *handle, return result; } -static int smb_full_audit_utime(vfs_handle_struct *handle, - const char *path, struct utimbuf *times) +static int smb_full_audit_ntimes(vfs_handle_struct *handle, + const char *path, const struct timespec ts[2]) { int result; - result = SMB_VFS_NEXT_UTIME(handle, path, times); + result = SMB_VFS_NEXT_NTIMES(handle, path, ts); - do_log(SMB_VFS_OP_UTIME, (result >= 0), handle, "%s", path); + do_log(SMB_VFS_OP_NTIMES, (result >= 0), handle, "%s", path); return result; } @@ -1405,6 +1420,35 @@ static char *smb_full_audit_realpath(vfs_handle_struct *handle, return result; } +static NTSTATUS smb_full_audit_notify_watch(struct vfs_handle_struct *handle, + struct sys_notify_context *ctx, + struct notify_entry *e, + void (*callback)(struct sys_notify_context *ctx, + void *private_data, + struct notify_event *ev), + void *private_data, void *handle_p) +{ + NTSTATUS result; + + result = SMB_VFS_NEXT_NOTIFY_WATCH(handle, ctx, e, callback, private_data, handle_p); + + do_log(SMB_VFS_OP_NOTIFY_WATCH, NT_STATUS_IS_OK(result), handle, ""); + + return result; +} + +static int smb_full_audit_chflags(vfs_handle_struct *handle, + const char *path, uint flags) +{ + int result; + + result = SMB_VFS_NEXT_CHFLAGS(handle, path, flags); + + do_log(SMB_VFS_OP_CHFLAGS, (result != 0), handle, "%s", path); + + return result; +} + static size_t smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info, SEC_DESC **ppdesc) diff --git a/source/modules/vfs_netatalk.c b/source/modules/vfs_netatalk.c index 7176919a7dc..efcc9816794 100644 --- a/source/modules/vfs_netatalk.c +++ b/source/modules/vfs_netatalk.c @@ -241,7 +241,7 @@ static int atalk_rename(struct vfs_handle_struct *handle, const char *oldname, c if (atalk_build_paths(ctx, handle->conn->origpath, oldname, &adbl_path, &orig_path, &adbl_info, &orig_info) != 0) - return ret; + goto exit_rename; if (S_ISDIR(orig_info.st_mode) || S_ISREG(orig_info.st_mode)) { DEBUG(3, ("ATALK: %s has passed..\n", adbl_path)); @@ -297,7 +297,7 @@ static int atalk_unlink(struct vfs_handle_struct *handle, const char *path) if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path, &adbl_info, &orig_info) != 0) - return ret; + goto exit_unlink; if (S_ISDIR(orig_info.st_mode) || S_ISREG(orig_info.st_mode)) { DEBUG(3, ("ATALK: %s has passed..\n", adbl_path)); @@ -329,7 +329,7 @@ static int atalk_chmod(struct vfs_handle_struct *handle, const char *path, mode_ if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path, &adbl_info, &orig_info) != 0) - return ret; + goto exit_chmod; if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) { DEBUG(3, ("ATALK: %s has passed..\n", orig_path)); @@ -361,7 +361,7 @@ static int atalk_chown(struct vfs_handle_struct *handle, const char *path, uid_t if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path, &adbl_info, &orig_info) != 0) - return ret; + goto exit_chown; if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) { DEBUG(3, ("ATALK: %s has passed..\n", orig_path)); diff --git a/source/modules/vfs_recycle.c b/source/modules/vfs_recycle.c index 121454315fb..579cc94cf94 100644 --- a/source/modules/vfs_recycle.c +++ b/source/modules/vfs_recycle.c @@ -153,17 +153,30 @@ static const char **recycle_noversions(vfs_handle_struct *handle) return tmp_lp; } -static int recycle_maxsize(vfs_handle_struct *handle) +static SMB_OFF_T recycle_maxsize(vfs_handle_struct *handle) { - int maxsize; + SMB_OFF_T maxsize; - maxsize = lp_parm_int(SNUM(handle->conn), "recycle", "maxsize", -1); + maxsize = conv_str_size(lp_parm_const_string(SNUM(handle->conn), + "recycle", "maxsize", NULL)); - DEBUG(10, ("recycle: maxsize = %d\n", maxsize)); + DEBUG(10, ("recycle: maxsize = %lu\n", (long unsigned int)maxsize)); return maxsize; } +static SMB_OFF_T recycle_minsize(vfs_handle_struct *handle) +{ + SMB_OFF_T minsize; + + minsize = conv_str_size(lp_parm_const_string(SNUM(handle->conn), + "recycle", "minsize", NULL)); + + DEBUG(10, ("recycle: minsize = %lu\n", (long unsigned int)minsize)); + + return minsize; +} + static mode_t recycle_directory_mode(vfs_handle_struct *handle) { int dirmode; @@ -351,18 +364,16 @@ static BOOL matchparam(const char **haystack_list, const char *needle) static void recycle_do_touch(vfs_handle_struct *handle, const char *fname, BOOL touch_mtime) { SMB_STRUCT_STAT st; - struct utimbuf tb; - time_t currtime; + struct timespec ts[2]; if (SMB_VFS_NEXT_STAT(handle, fname, &st) != 0) { DEBUG(0,("recycle: stat for %s returned %s\n", fname, strerror(errno))); return; } - currtime = time(&currtime); - tb.actime = currtime; - tb.modtime = touch_mtime ? currtime : st.st_mtime; + ts[0] = timespec_current(); /* atime */ + ts[1] = touch_mtime ? ts[0] : get_mtimespec(&st); /* mtime */ - if (SMB_VFS_NEXT_UTIME(handle, fname, &tb) == -1 ) { + if (SMB_VFS_NEXT_NTIMES(handle, fname, ts) == -1 ) { DEBUG(0, ("recycle: touching %s failed, reason = %s\n", fname, strerror(errno))); } } @@ -381,7 +392,7 @@ static int recycle_unlink(vfs_handle_struct *handle, const char *file_name) const char *base; char *repository = NULL; int i = 1; - int maxsize; + SMB_OFF_T maxsize, minsize; SMB_OFF_T file_size; /* space_avail; */ BOOL exist; int rc = -1; @@ -431,6 +442,12 @@ static int recycle_unlink(vfs_handle_struct *handle, const char *file_name) rc = SMB_VFS_NEXT_UNLINK(handle, file_name); goto done; } + minsize = recycle_minsize(handle); + if(minsize > 0 && file_size < minsize) { + DEBUG(3, ("recycle: File %s lowers minimum recycle size, purging... \n", file_name)); + rc = SMB_VFS_NEXT_UNLINK(handle, file_name); + goto done; + } /* FIXME: this is wrong: moving files with rename does not change the disk space * allocation diff --git a/source/nsswitch/idmap.c b/source/nsswitch/idmap.c index a58959afe4c..c2a38fa9797 100644 --- a/source/nsswitch/idmap.c +++ b/source/nsswitch/idmap.c @@ -297,7 +297,6 @@ NTSTATUS idmap_init(void) char *p = NULL; const char *q = NULL; - DEBUG(0, ("WARNING: idmap backend is deprecated!\n")); compat = 1; if ( (compat_backend = talloc_strdup( idmap_ctx, *compat_list )) == NULL ) { @@ -337,6 +336,15 @@ NTSTATUS idmap_init(void) const char *parm_backend; char *config_option; + /* ignore BUILTIN and local MACHINE domains */ + if ( strequal(dom_list[i], "BUILTIN") + || strequal(dom_list[i], get_global_sam_name() ) ) + { + DEBUG(0,("idmap_init: Ignoring invalid domain %s\n", + dom_list[i])); + continue; + } + if (strequal(dom_list[i], lp_workgroup())) { pri_dom_is_in_list = True; } @@ -577,17 +585,22 @@ NTSTATUS idmap_init(void) alloc_methods = get_alloc_methods(alloc_backends, alloc_backend); } } - if ( ! alloc_methods) { - DEBUG(0, ("ERROR: Could not get methods for alloc backend %s\n", alloc_backend)); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } - - ret = alloc_methods->init(compat_params); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(0, ("ERROR: Initialization failed for alloc backend %s\n", alloc_backend)); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; + if ( alloc_methods) { + ret = alloc_methods->init(compat_params); + if ( ! NT_STATUS_IS_OK(ret)) { + DEBUG(0, ("idmap_init: Initialization failed for alloc " + "backend %s\n", alloc_backend)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + } else { + DEBUG(2, ("idmap_init: Unable to get methods for alloc backend %s\n", + alloc_backend)); + /* certain compat backends are just readonly */ + if ( compat ) + ret = NT_STATUS_OK; + else + ret = NT_STATUS_UNSUCCESSFUL; } /* cleanpu temporary strings */ @@ -595,7 +608,7 @@ NTSTATUS idmap_init(void) backend_init_status = NT_STATUS_OK; - return NT_STATUS_OK; + return ret; done: DEBUG(0, ("Aborting IDMAP Initialization ...\n")); diff --git a/source/nsswitch/idmap_ldap.c b/source/nsswitch/idmap_ldap.c index 8cccbcecf4c..f74372eceab 100644 --- a/source/nsswitch/idmap_ldap.c +++ b/source/nsswitch/idmap_ldap.c @@ -1283,6 +1283,9 @@ static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom, const struct id sid, (unsigned long)map->xid.id, type)); DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", ld_error ? ld_error : "(NULL)", ldap_err2string (rc))); + if (ld_error) { + ldap_memfree(ld_error); + } ret = NT_STATUS_UNSUCCESSFUL; goto done; } diff --git a/source/nsswitch/pam_winbind.c b/source/nsswitch/pam_winbind.c index d21c985feee..66f9a093144 100644 --- a/source/nsswitch/pam_winbind.c +++ b/source/nsswitch/pam_winbind.c @@ -436,7 +436,7 @@ static int pam_winbind_request(pam_handle_t * pamh, int ctrl, /* Fill in request and send down pipe */ init_request(request, req_type); - if (write_sock(request, sizeof(*request), 0) == -1) { + if (write_sock(request, sizeof(*request), 0, 1) == -1) { _pam_log(pamh, ctrl, LOG_ERR, "pam_winbind_request: write to socket failed!"); close_sock(); return PAM_SERVICE_ERR; @@ -1517,7 +1517,6 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, dictionary *d = NULL; char *username_ret = NULL; char *new_authtok_required = NULL; - char *combined_member = NULL; const char *real_username = NULL; /* parse arguments */ diff --git a/source/nsswitch/wb_common.c b/source/nsswitch/wb_common.c index 05d2a660e73..fb84373aa63 100644 --- a/source/nsswitch/wb_common.c +++ b/source/nsswitch/wb_common.c @@ -33,6 +33,7 @@ BOOL winbind_on( void ); /* Global variables. These are effectively the client state information */ int winbindd_fd = -1; /* fd for winbindd socket */ +static int is_privileged = 0; /* Free a response structure */ @@ -287,7 +288,7 @@ static int winbind_named_pipe_sock(const char *dir) /* Connect to winbindd socket */ -static int winbind_open_pipe_sock(int recursing) +static int winbind_open_pipe_sock(int recursing, int need_priv) { #ifdef HAVE_UNIXSOCKET static pid_t our_pid; @@ -300,6 +301,10 @@ static int winbind_open_pipe_sock(int recursing) close_sock(); our_pid = getpid(); } + + if ((need_priv != 0) && (is_privileged == 0)) { + close_sock(); + } if (winbindd_fd != -1) { return winbindd_fd; @@ -313,6 +318,8 @@ static int winbind_open_pipe_sock(int recursing) return -1; } + is_privileged = 0; + /* version-check the socket */ request.flags = WBFLAG_RECURSE; @@ -329,9 +336,14 @@ static int winbind_open_pipe_sock(int recursing) if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) { close(winbindd_fd); winbindd_fd = fd; + is_privileged = 1; } } + if ((need_priv != 0) && (is_privileged == 0)) { + return -1; + } + SAFE_FREE(response.extra_data.data); return winbindd_fd; @@ -342,7 +354,7 @@ static int winbind_open_pipe_sock(int recursing) /* Write data to winbindd socket */ -int write_sock(void *buffer, int count, int recursing) +int write_sock(void *buffer, int count, int recursing, int need_priv) { int result, nwritten; @@ -350,7 +362,7 @@ int write_sock(void *buffer, int count, int recursing) restart: - if (winbind_open_pipe_sock(recursing) == -1) { + if (winbind_open_pipe_sock(recursing, need_priv) == -1) { return -1; } @@ -536,7 +548,8 @@ BOOL winbind_env_set( void ) * send simple types of requests */ -NSS_STATUS winbindd_send_request(int req_type, struct winbindd_request *request) +NSS_STATUS winbindd_send_request(int req_type, int need_priv, + struct winbindd_request *request) { struct winbindd_request lrequest; @@ -555,12 +568,14 @@ NSS_STATUS winbindd_send_request(int req_type, struct winbindd_request *request) init_request(request, req_type); - if (write_sock(request, sizeof(*request), request->flags & WBFLAG_RECURSE) == -1) { + if (write_sock(request, sizeof(*request), + request->flags & WBFLAG_RECURSE, need_priv) == -1) { return NSS_STATUS_UNAVAIL; } if ((request->extra_len != 0) && - (write_sock(request->extra_data.data, request->extra_len, request->flags & WBFLAG_RECURSE) == -1)) { + (write_sock(request->extra_data.data, request->extra_len, + request->flags & WBFLAG_RECURSE, need_priv) == -1)) { return NSS_STATUS_UNAVAIL; } @@ -610,7 +625,25 @@ NSS_STATUS winbindd_request_response(int req_type, int count = 0; while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) { - status = winbindd_send_request(req_type, request); + status = winbindd_send_request(req_type, 0, request); + if (status != NSS_STATUS_SUCCESS) + return(status); + status = winbindd_get_response(response); + count += 1; + } + + return status; +} + +NSS_STATUS winbindd_priv_request_response(int req_type, + struct winbindd_request *request, + struct winbindd_response *response) +{ + NSS_STATUS status = NSS_STATUS_UNAVAIL; + int count = 0; + + while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) { + status = winbindd_send_request(req_type, 1, request); if (status != NSS_STATUS_SUCCESS) return(status); status = winbindd_get_response(response); diff --git a/source/nsswitch/winbind_client.h b/source/nsswitch/winbind_client.h index 1d3d379af00..d80aff37fa1 100644 --- a/source/nsswitch/winbind_client.h +++ b/source/nsswitch/winbind_client.h @@ -2,13 +2,16 @@ #include "winbindd_nss.h" void init_request(struct winbindd_request *req,int rq_type); -NSS_STATUS winbindd_send_request(int req_type, +NSS_STATUS winbindd_send_request(int req_type, int need_priv, struct winbindd_request *request); NSS_STATUS winbindd_get_response(struct winbindd_response *response); NSS_STATUS winbindd_request_response(int req_type, struct winbindd_request *request, struct winbindd_response *response); -int write_sock(void *buffer, int count, int recursing); +NSS_STATUS winbindd_priv_request_response(int req_type, + struct winbindd_request *request, + struct winbindd_response *response); +int write_sock(void *buffer, int count, int recursing, int need_priv); int read_reply(struct winbindd_response *response); void close_sock(void); void free_response(struct winbindd_response *response); diff --git a/source/nsswitch/winbind_nss_irix.c b/source/nsswitch/winbind_nss_irix.c index 2fbf3e0df82..5c6679f0442 100644 --- a/source/nsswitch/winbind_nss_irix.c +++ b/source/nsswitch/winbind_nss_irix.c @@ -454,7 +454,7 @@ send_next_request(nsd_file_t *rq, struct winbindd_request *request) nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) %d, timeout = %d sec\n", rq->f_cmd_data, timeout); - status = winbindd_send_request((int)rq->f_cmd_data,request); + status = winbindd_send_request((int)rq->f_cmd_data,request,0); SAFE_FREE(request); if (status != NSS_STATUS_SUCCESS) { diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c index 3ddb041ba07..3b518fe3206 100644 --- a/source/nsswitch/winbindd.c +++ b/source/nsswitch/winbindd.c @@ -726,6 +726,15 @@ static void process_loop(void) int maxfd, listen_sock, listen_priv_sock, selret; struct timeval timeout, ev_timeout; + /* Open Sockets here to get stuff going ASAP */ + listen_sock = open_winbindd_socket(); + listen_priv_sock = open_winbindd_priv_socket(); + + if (listen_sock == -1 || listen_priv_sock == -1) { + perror("open_winbind_socket"); + exit(1); + } + /* We'll be doing this a lot */ /* Handle messages */ @@ -745,14 +754,6 @@ static void process_loop(void) /* Initialise fd lists for select() */ - listen_sock = open_winbindd_socket(); - listen_priv_sock = open_winbindd_priv_socket(); - - if (listen_sock == -1 || listen_priv_sock == -1) { - perror("open_winbind_socket"); - exit(1); - } - maxfd = MAX(listen_sock, listen_priv_sock); FD_ZERO(&r_fds); diff --git a/source/nsswitch/winbindd.h b/source/nsswitch/winbindd.h index b9e07a2321b..198c655b2d3 100644 --- a/source/nsswitch/winbindd.h +++ b/source/nsswitch/winbindd.h @@ -40,6 +40,8 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND +#define WB_REPLACE_CHAR '_' + /* bits for fd_event.flags */ #define EVENT_FD_READ 1 #define EVENT_FD_WRITE 2 diff --git a/source/nsswitch/winbindd_ads.c b/source/nsswitch/winbindd_ads.c index ea6dc2870a0..3925228efc6 100644 --- a/source/nsswitch/winbindd_ads.c +++ b/source/nsswitch/winbindd_ads.c @@ -40,6 +40,8 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) { ADS_STRUCT *ads; ADS_STATUS status; + fstring dc_name; + struct in_addr dc_ip; DEBUG(10,("ads_cached_connection\n")); @@ -114,6 +116,12 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME; + /* Setup the server affinity cache. We don't reaally care + about the name. Just setup affinity and the KRB5_CONFIG + file. */ + + get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ip ); + status = ads_connect(ads); if (!ADS_ERR_OK(status) || !ads->config.realm) { DEBUG(1,("ads_connect for domain %s failed: %s\n", @@ -607,7 +615,6 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, const char *attrs[] = {"memberOf", NULL}; size_t num_groups = 0; DOM_SID *group_sids = NULL; - char *escaped_dn; int i; DEBUG(3,("ads: lookup_usergroups_memberof\n")); @@ -619,16 +626,9 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, goto done; } - if (!(escaped_dn = escape_ldap_string_alloc(user_dn))) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - rc = ads_search_retry_extended_dn(ads, &res, escaped_dn, attrs, + rc = ads_search_retry_extended_dn(ads, &res, user_dn, attrs, ADS_EXTENDED_DN_HEX_STRING); - SAFE_FREE(escaped_dn); - if (!ADS_ERR_OK(rc) || !res) { DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n", user_dn, ads_errstr(rc))); diff --git a/source/nsswitch/winbindd_cred_cache.c b/source/nsswitch/winbindd_cred_cache.c index d0904002dd9..f161587e7aa 100644 --- a/source/nsswitch/winbindd_cred_cache.c +++ b/source/nsswitch/winbindd_cred_cache.c @@ -517,6 +517,7 @@ static NTSTATUS store_memory_creds(struct WINBINDD_MEMORY_CREDS *memcredp, const if ((mlock(memcredp->nt_hash, memcredp->len)) == -1) { DEBUG(0,("failed to mlock memory: %s (%d)\n", strerror(errno), errno)); + SAFE_FREE(memcredp->nt_hash); return map_nt_error_from_unix(errno); } diff --git a/source/nsswitch/winbindd_dual.c b/source/nsswitch/winbindd_dual.c index 6324de9a2d9..26debd26745 100644 --- a/source/nsswitch/winbindd_dual.c +++ b/source/nsswitch/winbindd_dual.c @@ -573,8 +573,8 @@ void winbind_msg_online(int msg_type, struct process_id src, winbindd_flush_negative_conn_cache(domain); set_domain_online_request(domain); - /* Send an offline message to the idmap child when our - primary domain goes offline */ + /* Send an online message to the idmap child when our + primary domain comes back online */ if ( domain->primary ) { struct winbindd_child *idmap = idmap_child(); diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c index 7edb755f1c0..9cf6cc12e0f 100644 --- a/source/nsswitch/winbindd_group.c +++ b/source/nsswitch/winbindd_group.c @@ -228,10 +228,12 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, * from more than one domain, ie aliases. Thus we have to work it out * ourselves in a special routine. */ - if (domain->internal) - return fill_passdb_alias_grmem(domain, group_sid, + if (domain->internal) { + result = fill_passdb_alias_grmem(domain, group_sid, num_gr_mem, gr_mem, gr_mem_len); + goto done; + } if ( !((group_name_type==SID_NAME_DOM_GRP) || ((group_name_type==SID_NAME_ALIAS) && domain->primary)) ) @@ -506,7 +508,7 @@ void winbindd_getgrnam(struct winbindd_cli_state *state) /* Get rid and name type from name */ - ws_name_replace( name_group, '_' ); + ws_name_replace( name_group, WB_REPLACE_CHAR ); if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name, name_group, &group_sid, &name_type)) { @@ -1273,6 +1275,8 @@ void winbindd_getgroups(struct winbindd_cli_state *state) s->state = state; + ws_name_return( state->request.data.username, WB_REPLACE_CHAR ); + if (!parse_domain_user_talloc(state->mem_ctx, state->request.data.username, &s->domname, &s->username)) { diff --git a/source/nsswitch/winbindd_pam.c b/source/nsswitch/winbindd_pam.c index 2e679c37dcf..6ee548292cc 100644 --- a/source/nsswitch/winbindd_pam.c +++ b/source/nsswitch/winbindd_pam.c @@ -744,6 +744,8 @@ void winbindd_pam_auth(struct winbindd_cli_state *state) /* Parse domain and username */ + ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR ); + if (!canonicalize_username(state->request.data.auth.user, name_domain, name_user)) { set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER); @@ -1332,6 +1334,8 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, /* Parse domain and username */ + ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR ); + parse_domain_user(state->request.data.auth.user, name_domain, name_user); if (domain->online == False) { @@ -2088,7 +2092,9 @@ void winbindd_pam_logoff(struct winbindd_cli_state *state) { struct winbindd_domain *domain; fstring name_domain, user; - + uid_t caller_uid = (uid_t)-1; + uid_t request_uid = state->request.data.logoff.uid; + DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid, state->request.data.logoff.user)); @@ -2099,6 +2105,10 @@ void winbindd_pam_logoff(struct winbindd_cli_state *state) state->request.data.logoff.krb5ccname [sizeof(state->request.data.logoff.krb5ccname)-1]='\0'; + if (request_uid == (gid_t)-1) { + goto failed; + } + if (!canonicalize_username(state->request.data.logoff.user, name_domain, user)) { goto failed; } @@ -2107,6 +2117,28 @@ void winbindd_pam_logoff(struct winbindd_cli_state *state) goto failed; } + if ((sys_getpeereid(state->sock, &caller_uid)) != 0) { + DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n", + strerror(errno))); + goto failed; + } + + switch (caller_uid) { + case -1: + goto failed; + case 0: + /* root must be able to logoff any user - gd */ + state->request.data.logoff.uid = request_uid; + break; + default: + if (caller_uid != request_uid) { + DEBUG(1,("winbindd_pam_logoff: caller requested invalid uid\n")); + goto failed; + } + state->request.data.logoff.uid = caller_uid; + break; + } + sendto_domain(state, domain); return; diff --git a/source/nsswitch/winbindd_rpc.c b/source/nsswitch/winbindd_rpc.c index 11d9fe0dbbd..3707f0311f8 100644 --- a/source/nsswitch/winbindd_rpc.c +++ b/source/nsswitch/winbindd_rpc.c @@ -262,7 +262,7 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain, return NT_STATUS_NO_MEMORY; } - ws_name_return( full_name, '_' ); + ws_name_return( full_name, WB_REPLACE_CHAR ); DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", full_name?full_name:"", domain_name )); @@ -317,7 +317,7 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain, *domain_name = domains[0]; *name = names[0]; - ws_name_replace( *name, '_' ); + ws_name_replace( *name, WB_REPLACE_CHAR ); DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name)); return NT_STATUS_OK; @@ -369,7 +369,7 @@ NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain, ret_names = *names; for (i=0; i<num_rids; i++) { if ((*types)[i] != SID_NAME_UNKNOWN) { - ws_name_replace( ret_names[i], '_' ); + ws_name_replace( ret_names[i], WB_REPLACE_CHAR ); *domain_name = domains[i]; } } diff --git a/source/nsswitch/winbindd_user.c b/source/nsswitch/winbindd_user.c index 47a7364e3a7..ce677198fff 100644 --- a/source/nsswitch/winbindd_user.c +++ b/source/nsswitch/winbindd_user.c @@ -243,7 +243,7 @@ static void getpwsid_queryuser_recv(void *private_data, BOOL success, strlower_m( username ); s->username = talloc_strdup(s->state->mem_ctx, username); - ws_name_replace( s->username, '_' ); + ws_name_replace( s->username, WB_REPLACE_CHAR ); s->fullname = talloc_strdup(s->state->mem_ctx, full_name); s->homedir = talloc_strdup(s->state->mem_ctx, homedir); @@ -262,7 +262,7 @@ static void getpwsid_sid2uid_recv(void *private_data, BOOL success, uid_t uid) talloc_get_type_abort(private_data, struct getpwsid_state); if (!success) { - DEBUG(5, ("Could not query user's %s\\%s uid\n", + DEBUG(5, ("Could not query uid for user %s\\%s\n", s->domain->name, s->username)); request_error(s->state); return; @@ -289,7 +289,7 @@ static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid) if ( s->gid == (gid_t)-1 ) { if (!success) { - DEBUG(5, ("Could not query user's %s\\%s\n gid", + DEBUG(5, ("Could not query gid for user %s\\%s\n", s->domain->name, s->username)); goto failed; } @@ -345,6 +345,8 @@ void winbindd_getpwnam(struct winbindd_cli_state *state) DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid, state->request.data.username)); + ws_name_return( state->request.data.username, WB_REPLACE_CHAR ); + if (!parse_domain_user(state->request.data.username, domname, username)) { DEBUG(5, ("Could not parse domain user: %s\n", diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 5d6a0c4ff54..85c1f4a9b64 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -229,7 +229,6 @@ typedef struct { int winbind_cache_time; int winbind_max_idle_children; char **szWinbindNssInfo; - int iLockSpinCount; int iLockSpinTime; char *szLdapMachineSuffix; char *szLdapUserSuffix; @@ -290,6 +289,7 @@ typedef struct { BOOL bClientNTLMv2Auth; BOOL bClientPlaintextAuth; BOOL bClientUseSpnego; + BOOL bDebugPrefixTimestamp; BOOL bDebugHiresTimestamp; BOOL bDebugPid; BOOL bDebugUid; @@ -953,6 +953,7 @@ static struct parm_struct parm_table[] = { {"max log size", P_INTEGER, P_GLOBAL, &Globals.max_log_size, NULL, NULL, FLAG_ADVANCED}, {"debug timestamp", P_BOOL, P_GLOBAL, &Globals.bTimestampLogs, NULL, NULL, FLAG_ADVANCED}, {"timestamp logs", P_BOOL, P_GLOBAL, &Globals.bTimestampLogs, NULL, NULL, FLAG_ADVANCED}, + {"debug prefix timestamp", P_BOOL, P_GLOBAL, &Globals.bDebugPrefixTimestamp, NULL, NULL, FLAG_ADVANCED}, {"debug hires timestamp", P_BOOL, P_GLOBAL, &Globals.bDebugHiresTimestamp, NULL, NULL, FLAG_ADVANCED}, {"debug pid", P_BOOL, P_GLOBAL, &Globals.bDebugPid, NULL, NULL, FLAG_ADVANCED}, {"debug uid", P_BOOL, P_GLOBAL, &Globals.bDebugUid, NULL, NULL, FLAG_ADVANCED}, @@ -1156,7 +1157,6 @@ static struct parm_struct parm_table[] = { {"fake oplocks", P_BOOL, P_LOCAL, &sDefault.bFakeOplocks, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, {"kernel oplocks", P_BOOL, P_GLOBAL, &Globals.bKernelOplocks, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL}, {"locking", P_BOOL, P_LOCAL, &sDefault.bLocking, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, - {"lock spin count", P_INTEGER, P_GLOBAL, &Globals.iLockSpinCount, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL}, {"lock spin time", P_INTEGER, P_GLOBAL, &Globals.iLockSpinTime, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL}, {"oplocks", P_BOOL, P_LOCAL, &sDefault.bOpLocks, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, @@ -1269,14 +1269,14 @@ static struct parm_struct parm_table[] = { {"passdb expand explicit", P_BOOL, P_GLOBAL, &Globals.bPassdbExpandExplicit, NULL, NULL, FLAG_ADVANCED}, {"idmap domains", P_LIST, P_GLOBAL, &Globals.szIdmapDomains, NULL, NULL, FLAG_ADVANCED}, - {"idmap backend", P_LIST, P_GLOBAL, &Globals.szIdmapBackend, NULL, NULL, FLAG_ADVANCED | FLAG_DEPRECATED }, + {"idmap backend", P_LIST, P_GLOBAL, &Globals.szIdmapBackend, NULL, NULL, FLAG_ADVANCED }, {"idmap alloc backend", P_STRING, P_GLOBAL, &Globals.szIdmapAllocBackend, NULL, NULL, FLAG_ADVANCED}, {"idmap expire time", P_INTEGER, P_GLOBAL, &Globals.iIdmapExpireTime, NULL, NULL, FLAG_ADVANCED}, {"idmap negative time", P_INTEGER, P_GLOBAL, &Globals.iIdmapNegativeTime, NULL, NULL, FLAG_ADVANCED}, - {"idmap uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED | FLAG_DEPRECATED }, - {"winbind uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_HIDE | FLAG_DEPRECATED }, - {"idmap gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_ADVANCED | FLAG_DEPRECATED }, - {"winbind gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_HIDE | FLAG_DEPRECATED }, + {"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_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_HIDE }, {"template homedir", P_STRING, P_GLOBAL, &Globals.szTemplateHomedir, NULL, NULL, FLAG_ADVANCED}, {"template shell", P_STRING, P_GLOBAL, &Globals.szTemplateShell, NULL, NULL, FLAG_ADVANCED}, {"winbind separator", P_STRING, P_GLOBAL, &Globals.szWinbindSeparator, NULL, NULL, FLAG_ADVANCED}, @@ -1517,6 +1517,7 @@ static void init_globals(BOOL first_time_only) Globals.bSyslogOnly = False; Globals.bTimestampLogs = True; string_set(&Globals.szLogLevel, "0"); + Globals.bDebugPrefixTimestamp = False; Globals.bDebugHiresTimestamp = False; Globals.bDebugPid = False; Globals.bDebugUid = False; @@ -1557,7 +1558,6 @@ static void init_globals(BOOL first_time_only) Globals.map_to_guest = 0; /* By Default, "Never" */ Globals.oplock_break_wait_time = 0; /* By Default, 0 msecs. */ Globals.enhanced_browsing = True; - Globals.iLockSpinCount = 0; /* Unused. */ Globals.iLockSpinTime = WINDOWS_MINIMUM_LOCK_TIMEOUT_MS; /* msec. */ #ifdef MMAP_BLACKLIST Globals.bUseMmap = False; @@ -1945,6 +1945,7 @@ FN_GLOBAL_INTEGER(lp_client_schannel, &Globals.clientSchannel) FN_GLOBAL_INTEGER(lp_server_schannel, &Globals.serverSchannel) FN_GLOBAL_BOOL(lp_syslog_only, &Globals.bSyslogOnly) FN_GLOBAL_BOOL(lp_timestamp_logs, &Globals.bTimestampLogs) +FN_GLOBAL_BOOL(lp_debug_prefix_timestamp, &Globals.bDebugPrefixTimestamp) FN_GLOBAL_BOOL(lp_debug_hires_timestamp, &Globals.bDebugHiresTimestamp) FN_GLOBAL_BOOL(lp_debug_pid, &Globals.bDebugPid) FN_GLOBAL_BOOL(lp_debug_uid, &Globals.bDebugUid) @@ -2010,7 +2011,6 @@ FN_GLOBAL_INTEGER(lp_lm_interval, &Globals.lm_interval) FN_GLOBAL_INTEGER(lp_machine_password_timeout, &Globals.machine_password_timeout) FN_GLOBAL_INTEGER(lp_map_to_guest, &Globals.map_to_guest) 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_spin_time, &Globals.iLockSpinTime) FN_GLOBAL_INTEGER(lp_usershare_max_shares, &Globals.iUsershareMaxShares) diff --git a/source/passdb/lookup_sid.c b/source/passdb/lookup_sid.c index 0b596fc8d7f..d76cc07ce1e 100644 --- a/source/passdb/lookup_sid.c +++ b/source/passdb/lookup_sid.c @@ -411,9 +411,15 @@ static BOOL wb_lookup_rids(TALLOC_CTX *mem_ctx, names[i] = ""; types[i] = SID_NAME_UNKNOWN; } + TALLOC_FREE(tmp_ctx); return True; } + if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) { + TALLOC_FREE(tmp_ctx); + return False; + } + /* * winbind_lookup_rids allocates its own array. We've been given the * array, so copy it over @@ -1115,7 +1121,7 @@ void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) *THE LEGACY* convert uid_t to SID function. *****************************************************************/ -void legacy_uid_to_sid(DOM_SID *psid, uid_t uid) +static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid) { uint32 rid; BOOL ret; @@ -1149,7 +1155,7 @@ void legacy_uid_to_sid(DOM_SID *psid, uid_t uid) *THE LEGACY* convert gid_t to SID function. *****************************************************************/ -void legacy_gid_to_sid(DOM_SID *psid, gid_t gid) +static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid) { BOOL ret; @@ -1180,7 +1186,7 @@ void legacy_gid_to_sid(DOM_SID *psid, gid_t gid) *THE LEGACY* convert SID to uid function. *****************************************************************/ -BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid) +static BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid) { enum lsa_SidType type; uint32 rid; @@ -1229,7 +1235,7 @@ done: Group mapping is used for gids that maps to Wellknown SIDs *****************************************************************/ -BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid) +static BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid) { uint32 rid; GROUP_MAP map; diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c index 533b936efd9..c4c53c30664 100644 --- a/source/passdb/pdb_ldap.c +++ b/source/passdb/pdb_ldap.c @@ -2049,14 +2049,25 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct s TALLOC_FREE( attr_list ); if (num_result == 0) { + char *escape_username; /* Check if we need to add an entry */ DEBUG(3,("ldapsam_add_sam_account: Adding new user\n")); ldap_op = LDAP_MOD_ADD; + + escape_username = escape_rdn_val_string_alloc(username); + if (!escape_username) { + DEBUG(0, ("Out of memory!\n")); + ldap_msgfree(result); + return NT_STATUS_NO_MEMORY; + } + if (username[strlen(username)-1] == '$') { - slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ()); + slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", escape_username, lp_ldap_machine_suffix ()); } else { - slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ()); + slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", escape_username, lp_ldap_user_suffix ()); } + + SAFE_FREE(escape_username); } if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd, @@ -2415,11 +2426,22 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods, } for (memberuid = values; *memberuid != NULL; memberuid += 1) { - filter = talloc_asprintf_append(filter, "(uid=%s)", *memberuid); + char *escape_memberuid; + + escape_memberuid = escape_ldap_string_alloc(*memberuid); + if (escape_memberuid == NULL) { + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + filter = talloc_asprintf_append(filter, "(uid=%s)", escape_memberuid); if (filter == NULL) { + SAFE_FREE(escape_memberuid); ret = NT_STATUS_NO_MEMORY; goto done; } + + SAFE_FREE(escape_memberuid); } filter = talloc_asprintf_append(filter, "))"); @@ -4773,6 +4795,8 @@ static NTSTATUS ldapsam_create_user(struct pdb_methods *my_methods, smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SAMBASAMACCOUNT); if (add_posix) { + char *escape_name; + DEBUG(3,("ldapsam_create_user: Creating new posix user\n")); /* retrieve the Domain Users group gid */ @@ -4799,12 +4823,21 @@ static NTSTATUS ldapsam_create_user(struct pdb_methods *my_methods, } uidstr = talloc_asprintf(tmp_ctx, "%d", uid); gidstr = talloc_asprintf(tmp_ctx, "%d", gid); + + escape_name = escape_rdn_val_string_alloc(name); + if (!escape_name) { + DEBUG (0, ("ldapsam_create_user: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + if (is_machine) { - dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", name, lp_ldap_machine_suffix ()); + dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", escape_name, lp_ldap_machine_suffix ()); } else { - dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", name, lp_ldap_user_suffix ()); + dn = talloc_asprintf(tmp_ctx, "uid=%s,%s", escape_name, lp_ldap_user_suffix ()); } + SAFE_FREE(escape_name); + if (!homedir || !shell || !uidstr || !gidstr || !dn) { DEBUG (0, ("ldapsam_create_user: Out of memory!\n")); return NT_STATUS_NO_MEMORY; @@ -4986,6 +5019,8 @@ static NTSTATUS ldapsam_create_dom_group(struct pdb_methods *my_methods, } if (num_result == 0) { + char *escape_name; + DEBUG(3,("ldapsam_create_user: Creating new posix group\n")); is_new_entry = True; @@ -4997,7 +5032,16 @@ static NTSTATUS ldapsam_create_dom_group(struct pdb_methods *my_methods, } gidstr = talloc_asprintf(tmp_ctx, "%d", gid); - dn = talloc_asprintf(tmp_ctx, "cn=%s,%s", name, lp_ldap_group_suffix()); + + escape_name = escape_rdn_val_string_alloc(name); + if (!escape_name) { + DEBUG (0, ("ldapsam_create_group: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + dn = talloc_asprintf(tmp_ctx, "cn=%s,%s", escape_name, lp_ldap_group_suffix()); + + SAFE_FREE(escape_name); if (!gidstr || !dn) { DEBUG (0, ("ldapsam_create_group: Out of memory!\n")); @@ -5335,6 +5379,7 @@ static NTSTATUS ldapsam_set_primary_group(struct pdb_methods *my_methods, uint32 num_result; LDAPMod **mods = NULL; char *filter; + char *escape_username; char *gidstr; const char *dn = NULL; gid_t gid; @@ -5351,14 +5396,22 @@ static NTSTATUS ldapsam_set_primary_group(struct pdb_methods *my_methods, DEBUG(0,("ldapsam_set_primary_group: Out of Memory!\n")); return NT_STATUS_NO_MEMORY; } - + + escape_username = escape_ldap_string_alloc(pdb_get_username(sampass)); + if (escape_username== NULL) { + return NT_STATUS_NO_MEMORY; + } + filter = talloc_asprintf(mem_ctx, "(&(uid=%s)" "(objectClass=%s)" "(objectClass=%s))", - pdb_get_username(sampass), + escape_username, LDAP_OBJ_POSIXACCOUNT, LDAP_OBJ_SAMBASAMACCOUNT); + + SAFE_FREE(escape_username); + if (filter == NULL) { return NT_STATUS_NO_MEMORY; } @@ -5620,6 +5673,7 @@ NTSTATUS pdb_init_ldapsam(struct pdb_methods **pdb_method, const char *location) dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); if (!dn) { + ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } @@ -5636,6 +5690,7 @@ NTSTATUS pdb_init_ldapsam(struct pdb_methods **pdb_method, const char *location) if (!string_to_sid(&ldap_domain_sid, domain_sid_string)) { DEBUG(1, ("pdb_init_ldapsam: SID [%s] could not be " "read as a valid SID\n", domain_sid_string)); + ldap_msgfree(result); return NT_STATUS_INVALID_PARAMETER; } found_sid = secrets_fetch_domain_sid(ldap_state->domain_name, diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index 063e4b3e175..8829ef2b0c2 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -1036,13 +1036,12 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 char *buf = NULL; ssize_t byte_count; - if ((buf=(char *)SMB_MALLOC(PE_HEADER_SIZE)) == NULL) { - DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n", - fname, PE_HEADER_SIZE)); + if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) { + DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n", + fname, DOS_HEADER_SIZE)); goto error_exit; } - /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */ if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) { DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n", fname, (unsigned long)byte_count)); @@ -1064,7 +1063,8 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 goto no_version_info; } - if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) { + /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */ + if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) { DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n", fname, (unsigned long)byte_count)); /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ @@ -1075,13 +1075,13 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) { unsigned int num_sections; unsigned int section_table_bytes; - - if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) { - DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n", - fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET))); - /* At this point, we assume the file is in error. It still could be somthing - * else besides a PE file, but it unlikely at this point. - */ + + /* Just skip over optional header to get to section table */ + if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, + SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE), + SEEK_CUR) == (SMB_OFF_T)-1) { + DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n", + fname, errno)); goto error_exit; } @@ -1823,7 +1823,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &st); - if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| + if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); @@ -1839,7 +1839,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &st); - if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| + if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); @@ -1857,7 +1857,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &st); - if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| + if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); @@ -1876,7 +1876,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &st); - if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| + if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); @@ -1904,7 +1904,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &st); - if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, + if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -3034,7 +3034,7 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, { ADS_STATUS ads_rc; LDAPMessage *res; - char *prt_dn = NULL, *srv_dn, *srv_cn_0; + char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped; char *srv_dn_utf8, **srv_cn_utf8; TALLOC_CTX *ctx; ADS_MODLIST mods; @@ -3080,11 +3080,29 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, ldap_memfree(srv_dn_utf8); ldap_memfree(srv_cn_utf8); - asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_0, - printer->info_2->sharename, srv_dn); + srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0); + if (!srv_cn_escaped) { + SAFE_FREE(srv_cn_0); + ldap_memfree(srv_dn_utf8); + ads_destroy(&ads); + return WERR_SERVER_UNAVAILABLE; + } + sharename_escaped = escape_rdn_val_string_alloc(printer->info_2->sharename); + if (!sharename_escaped) { + SAFE_FREE(srv_cn_escaped); + SAFE_FREE(srv_cn_0); + ldap_memfree(srv_dn_utf8); + ads_destroy(&ads); + return WERR_SERVER_UNAVAILABLE; + } + + + asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn); SAFE_FREE(srv_dn); SAFE_FREE(srv_cn_0); + SAFE_FREE(srv_cn_escaped); + SAFE_FREE(sharename_escaped); /* build the ads mods */ ctx = talloc_init("nt_printer_publish_ads"); @@ -3725,9 +3743,7 @@ static void map_to_os2_driver(fstring drivername) ****************************************************************************/ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info, const char *servername, const char* sharename) { - int snum; - - snum = lp_servicenumber(sharename); + int snum = lp_servicenumber(sharename); slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername); slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s", @@ -3751,6 +3767,15 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info, const char fstrcpy(info->printprocessor, "winprint"); fstrcpy(info->datatype, "RAW"); +#ifdef HAVE_CUPS + if ( (enum printing_types)lp_printing(snum) == PRINT_CUPS ) { + /* Pull the location and comment strings from cups if we don't + already have one */ + if ( !strlen(info->location) || !strlen(info->comment) ) + cups_pull_comment_location( info ); + } +#endif + info->attributes = PRINTER_ATTRIBUTE_SAMBA; info->starttime = 0; /* Minutes since 12:00am GMT */ @@ -3846,6 +3871,15 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info, const char *servern fstrcpy(info->printername, printername); +#ifdef HAVE_CUPS + if ( (enum printing_types)lp_printing(snum) == PRINT_CUPS ) { + /* Pull the location and comment strings from cups if we don't + already have one */ + if ( !strlen(info->location) || !strlen(info->comment) ) + cups_pull_comment_location( info ); + } +#endif + len += unpack_devicemode(&info->devmode,dbuf.dptr+len, dbuf.dsize-len); /* diff --git a/source/printing/print_cups.c b/source/printing/print_cups.c index 2c942627c6b..0fa73e5a6ca 100644 --- a/source/printing/print_cups.c +++ b/source/printing/print_cups.c @@ -1198,6 +1198,145 @@ struct printif cups_printif = cups_job_submit, }; +BOOL cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer) +{ + http_t *http = NULL; /* HTTP connection to server */ + ipp_t *request = NULL, /* IPP Request */ + *response = NULL; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language = NULL; /* Default language */ + char *name, /* printer-name attribute */ + *info, /* printer-info attribute */ + *location; /* printer-location attribute */ + char uri[HTTP_MAX_URI]; + static const char *requested[] =/* Requested attributes */ + { + "printer-name", + "printer-info", + "printer-location" + }; + BOOL ret = False; + + DEBUG(5, ("pulling %s location\n", printer->sharename)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + + /* + * Try to connect to the server... + */ + + if ((http = cups_connect()) == NULL) { + goto out; + } + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s", + lp_cups_server(), printer->sharename); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requested-attributes", + (sizeof(requested) / sizeof(requested[0])), + NULL, requested); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) == NULL) { + DEBUG(0,("Unable to get printer attributes - %s\n", + ippErrorString(cupsLastError()))); + goto out; + } + + for (attr = response->attrs; attr != NULL;) { + /* + * Skip leading attributes until we hit a printer... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Pull the needed attributes from this printer... + */ + + name = NULL; + info = NULL; + location = NULL; + + while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) { + /* Grab the comment if we don't have one */ + if ( (strcmp(attr->name, "printer-info") == 0) + && (attr->value_tag == IPP_TAG_TEXT) + && !strlen(printer->comment) ) + { + DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n", + attr->values[0].string.text)); + pstrcpy(printer->comment,attr->values[0].string.text); + } + + /* Grab the location if we don't have one */ + if ( (strcmp(attr->name, "printer-location") == 0) + && (attr->value_tag == IPP_TAG_TEXT) + && !strlen(printer->location) ) + { + DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n", + attr->values[0].string.text)); + fstrcpy(printer->location,attr->values[0].string.text); + } + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (name == NULL) + break; + + } + + ippDelete(response); + response = NULL; + + ret = True; + + out: + if (response) + ippDelete(response); + + if (language) + cupsLangFree(language); + + if (http) + httpClose(http); + + return ret; +} + #else /* this keeps fussy compilers happy */ void print_cups_dummy(void); diff --git a/source/profile/profile.c b/source/profile/profile.c index 4568678739f..69c240061e1 100644 --- a/source/profile/profile.c +++ b/source/profile/profile.c @@ -284,7 +284,7 @@ BOOL profile_setup(BOOL rdonly) "syscall_fchown", /* PR_VALUE_SYSCALL_FCHOWN */ "syscall_chdir", /* PR_VALUE_SYSCALL_CHDIR */ "syscall_getwd", /* PR_VALUE_SYSCALL_GETWD */ - "syscall_utime", /* PR_VALUE_SYSCALL_UTIME */ + "syscall_ntimes", /* PR_VALUE_SYSCALL_NTIMES */ "syscall_ftruncate", /* PR_VALUE_SYSCALL_FTRUNCATE */ "syscall_fcntl_lock", /* PR_VALUE_SYSCALL_FCNTL_LOCK */ "syscall_kernel_flock", /* PR_VALUE_SYSCALL_KERNEL_FLOCK */ diff --git a/source/rpc_client/cli_srvsvc.c b/source/rpc_client/cli_srvsvc.c index 0d50e94d577..7b4818b4b06 100644 --- a/source/rpc_client/cli_srvsvc.c +++ b/source/rpc_client/cli_srvsvc.c @@ -5,6 +5,8 @@ Copyright (C) Tim Potter 2001 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002 Copyright (C) Jeremy Allison 2005. + Copyright (C) Gerald (Jerry) Carter 2006. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -537,38 +539,37 @@ WERROR rpccli_srvsvc_net_file_enum(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ ZERO_STRUCTP(ctr); - ctr->switch_value = file_level; + ctr->level = file_level; ctr->num_entries = ctr->num_entries2 = r.ctr.num_entries; switch(file_level) { case 3: - ctr->file.info3 = TALLOC_ARRAY(mem_ctx, SRV_FILE_INFO_3, ctr->num_entries); - if (ctr->file.info3 == NULL) { + if ( (ctr->file.info3 = TALLOC_ARRAY(mem_ctx, FILE_INFO_3, ctr->num_entries)) == NULL ) { return WERR_NOMEM; } - memset(ctr->file.info3, 0, - sizeof(SRV_FILE_INFO_3) * ctr->num_entries); + memset(ctr->file.info3, 0, sizeof(FILE_INFO_3) * ctr->num_entries); for (i = 0; i < r.ctr.num_entries; i++) { - SRV_FILE_INFO_3 *info3 = &ctr->file.info3[i]; + FILE_INFO_3 *info3 = &ctr->file.info3[i]; char *s; /* Copy pointer crap */ - memcpy(&info3->info_3, &r.ctr.file.info3[i].info_3, - sizeof(FILE_INFO_3)); + memcpy(info3, &r.ctr.file.info3[i], sizeof(FILE_INFO_3)); /* Duplicate strings */ - s = unistr2_tdup(mem_ctx, &r.ctr.file.info3[i].info_3_str.uni_path_name); - if (s) - init_unistr2(&info3->info_3_str.uni_path_name, s, UNI_STR_TERMINATE); + if ( (s = unistr2_tdup(mem_ctx, r.ctr.file.info3[i].path)) != NULL ) { + info3->path = TALLOC_P( mem_ctx, UNISTR2 ); + init_unistr2(info3->path, s, UNI_STR_TERMINATE); + } - s = unistr2_tdup(mem_ctx, &r.ctr.file.info3[i].info_3_str.uni_user_name); - if (s) - init_unistr2(&info3->info_3_str.uni_user_name, s, UNI_STR_TERMINATE); + if ( (s = unistr2_tdup(mem_ctx, r.ctr.file.info3[i].user)) != NULL ) { + info3->user = TALLOC_P( mem_ctx, UNISTR2 ); + init_unistr2(info3->user, s, UNI_STR_TERMINATE); + } } diff --git a/source/rpc_parse/parse_srv.c b/source/rpc_parse/parse_srv.c index 7d15eda630f..8ed67872430 100644 --- a/source/rpc_parse/parse_srv.c +++ b/source/rpc_parse/parse_srv.c @@ -7,6 +7,7 @@ * Copyright (C) Jeremy Allison 1999, * Copyright (C) Nigel Williams 2001, * Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2002. + * Copyright (C) Gerald (Jerry) Carter 2006. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1588,64 +1589,17 @@ BOOL srv_io_r_net_share_del(const char *desc, SRV_R_NET_SHARE_DEL *q_n, prs_stru Inits a SESS_INFO_0_STR structure ********************************************************************/ -void init_srv_sess_info0_str(SESS_INFO_0_STR *ss0, const char *name) +void init_srv_sess_info0( SESS_INFO_0 *ss0, const char *name ) { - DEBUG(5,("init_srv_sess_info0_str\n")); + ZERO_STRUCTP( ss0 ); - init_unistr2(&ss0->uni_name, name, UNI_STR_TERMINATE); -} - -/******************************************************************* - Reads or writes a structure. -********************************************************************/ - -static BOOL srv_io_sess_info0_str(const char *desc, SESS_INFO_0_STR *ss0, prs_struct *ps, int depth) -{ - if (ss0 == NULL) - return False; - - prs_debug(ps, depth, desc, "srv_io_sess_info0_str"); - depth++; - - if(!prs_align(ps)) - return False; - - if(!smb_io_unistr2("", &ss0->uni_name, True, ps, depth)) - return False; - - return True; -} - -/******************************************************************* - Inits a SESS_INFO_0 structure -********************************************************************/ - -void init_srv_sess_info0(SESS_INFO_0 *ss0, const char *name) -{ - DEBUG(5,("init_srv_sess_info0: %s\n", name)); - - ss0->ptr_name = (name != NULL) ? 1 : 0; -} - -/******************************************************************* - Reads or writes a structure. -********************************************************************/ - -static BOOL srv_io_sess_info0(const char *desc, SESS_INFO_0 *ss0, prs_struct *ps, int depth) -{ - if (ss0 == NULL) - return False; - - prs_debug(ps, depth, desc, "srv_io_sess_info0"); - depth++; - - if(!prs_align(ps)) - return False; - - if(!prs_uint32("ptr_name", ps, depth, &ss0->ptr_name)) - return False; - - return True; + if ( name ) { + if ( (ss0->sharename = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) { + DEBUG(0,("init_srv_sess_info0: talloc failed!\n")); + return; + } + init_unistr2( ss0->sharename, name, UNI_STR_TERMINATE ); + } } /******************************************************************* @@ -1681,13 +1635,15 @@ static BOOL srv_io_srv_sess_info_0(const char *desc, SRV_SESS_INFO_0 *ss0, prs_s SMB_ASSERT_ARRAY(ss0->info_0, num_entries); + /* first the pointers */ for (i = 0; i < num_entries; i++) { - if(!srv_io_sess_info0("", &ss0->info_0[i], ps, depth)) + if ( !prs_io_unistr2_p("", ps, depth, &ss0->info_0[i].sharename ) ) return False; } + /* now the strings */ for (i = 0; i < num_entries; i++) { - if(!srv_io_sess_info0_str("", &ss0->info_0_str[i], ps, depth)) + if ( !prs_io_unistr2("sharename", ps, depth, ss0->info_0[i].sharename )) return False; } @@ -1699,53 +1655,32 @@ static BOOL srv_io_srv_sess_info_0(const char *desc, SRV_SESS_INFO_0 *ss0, prs_s } /******************************************************************* - Inits a SESS_INFO_1_STR structure -********************************************************************/ - -void init_srv_sess_info1_str(SESS_INFO_1_STR *ss1, const char *name, const char *user) -{ - DEBUG(5,("init_srv_sess_info1_str\n")); - - init_unistr2(&ss1->uni_name, name, UNI_STR_TERMINATE); - init_unistr2(&ss1->uni_user, user, UNI_STR_TERMINATE); -} - -/******************************************************************* - Reads or writes a structure. -********************************************************************/ - -static BOOL srv_io_sess_info1_str(const char *desc, SESS_INFO_1_STR *ss1, prs_struct *ps, int depth) -{ - if (ss1 == NULL) - return False; - - prs_debug(ps, depth, desc, "srv_io_sess_info1_str"); - depth++; - - if(!prs_align(ps)) - return False; - - if(!smb_io_unistr2("", &ss1->uni_name, True, ps, depth)) - return False; - if(!smb_io_unistr2("", &(ss1->uni_user), True, ps, depth)) - return False; - - return True; -} - -/******************************************************************* Inits a SESS_INFO_1 structure ********************************************************************/ -void init_srv_sess_info1(SESS_INFO_1 *ss1, - const char *name, const char *user, - uint32 num_opens, uint32 open_time, uint32 idle_time, - uint32 user_flags) +void init_srv_sess_info1( SESS_INFO_1 *ss1, const char *name, const char *user, + uint32 num_opens, uint32 open_time, uint32 idle_time, + uint32 user_flags) { DEBUG(5,("init_srv_sess_info1: %s\n", name)); - ss1->ptr_name = (name != NULL) ? 1 : 0; - ss1->ptr_user = (user != NULL) ? 1 : 0; + ZERO_STRUCTP( ss1 ); + + if ( name ) { + if ( (ss1->sharename = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) { + DEBUG(0,("init_srv_sess_info0: talloc failed!\n")); + return; + } + init_unistr2( ss1->sharename, name, UNI_STR_TERMINATE ); + } + + if ( user ) { + if ( (ss1->username = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) { + DEBUG(0,("init_srv_sess_info0: talloc failed!\n")); + return; + } + init_unistr2( ss1->username, user, UNI_STR_TERMINATE ); + } ss1->num_opens = num_opens; ss1->open_time = open_time; @@ -1753,37 +1688,6 @@ void init_srv_sess_info1(SESS_INFO_1 *ss1, ss1->user_flags = user_flags; } -/******************************************************************* -reads or writes a structure. -********************************************************************/ - -static BOOL srv_io_sess_info1(const char *desc, SESS_INFO_1 *ss1, prs_struct *ps, int depth) -{ - if (ss1 == NULL) - return False; - - prs_debug(ps, depth, desc, "srv_io_sess_info1"); - depth++; - - if(!prs_align(ps)) - return False; - - if(!prs_uint32("ptr_name ", ps, depth, &ss1->ptr_name)) - return False; - if(!prs_uint32("ptr_user ", ps, depth, &ss1->ptr_user)) - return False; - - if(!prs_uint32("num_opens ", ps, depth, &ss1->num_opens)) - return False; - if(!prs_uint32("open_time ", ps, depth, &ss1->open_time)) - return False; - if(!prs_uint32("idle_time ", ps, depth, &ss1->idle_time)) - return False; - if(!prs_uint32("user_flags", ps, depth, &ss1->user_flags)) - return False; - - return True; -} /******************************************************************* Reads or writes a structure. @@ -1818,13 +1722,31 @@ static BOOL srv_io_srv_sess_info_1(const char *desc, SRV_SESS_INFO_1 *ss1, prs_s SMB_ASSERT_ARRAY(ss1->info_1, num_entries); + /* first the pointers and flags */ + for (i = 0; i < num_entries; i++) { - if(!srv_io_sess_info1("", &ss1->info_1[i], ps, depth)) + + if ( !prs_io_unistr2_p("", ps, depth, &ss1->info_1[i].sharename )) + return False; + if ( !prs_io_unistr2_p("", ps, depth, &ss1->info_1[i].username )) + return False; + + if(!prs_uint32("num_opens ", ps, depth, &ss1->info_1[i].num_opens)) + return False; + if(!prs_uint32("open_time ", ps, depth, &ss1->info_1[i].open_time)) + return False; + if(!prs_uint32("idle_time ", ps, depth, &ss1->info_1[i].idle_time)) + return False; + if(!prs_uint32("user_flags", ps, depth, &ss1->info_1[i].user_flags)) return False; } + /* now the strings */ + for (i = 0; i < num_entries; i++) { - if(!srv_io_sess_info1_str("", &ss1->info_1_str[i], ps, depth)) + if ( !prs_io_unistr2("", ps, depth, ss1->info_1[i].sharename )) + return False; + if ( !prs_io_unistr2("", ps, depth, ss1->info_1[i].username )) return False; } @@ -1884,36 +1806,12 @@ static BOOL srv_io_srv_sess_ctr(const char *desc, SRV_SESS_INFO_CTR **pp_ctr, pr } /******************************************************************* - Inits a SRV_Q_NET_SESS_ENUM structure. -********************************************************************/ - -void init_srv_q_net_sess_enum(SRV_Q_NET_SESS_ENUM *q_n, - const char *srv_name, const char *qual_name, - const char *user_name, uint32 sess_level, - SRV_SESS_INFO_CTR *ctr, uint32 preferred_len, - ENUM_HND *hnd) -{ - q_n->ctr = ctr; - - DEBUG(5,("init_q_net_sess_enum\n")); - - init_buf_unistr2(&q_n->uni_srv_name, &q_n->ptr_srv_name, srv_name); - init_buf_unistr2(&q_n->uni_qual_name, &q_n->ptr_qual_name, qual_name); - init_buf_unistr2(&q_n->uni_user_name, &q_n->ptr_user_name, user_name); - - q_n->sess_level = sess_level; - q_n->preferred_len = preferred_len; - - memcpy(&q_n->enum_hnd, hnd, sizeof(*hnd)); -} - -/******************************************************************* Reads or writes a structure. ********************************************************************/ -BOOL srv_io_q_net_sess_enum(const char *desc, SRV_Q_NET_SESS_ENUM *q_n, prs_struct *ps, int depth) +BOOL srv_io_q_net_sess_enum(const char *desc, SRV_Q_NET_SESS_ENUM *q_u, prs_struct *ps, int depth) { - if (q_n == NULL) + if (q_u == NULL) return False; prs_debug(ps, depth, desc, "srv_io_q_net_sess_enum"); @@ -1922,41 +1820,36 @@ BOOL srv_io_q_net_sess_enum(const char *desc, SRV_Q_NET_SESS_ENUM *q_n, prs_stru if(!prs_align(ps)) return False; - if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name)) - return False; - if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth)) + if(!prs_pointer("servername", ps, depth, (void**)&q_u->servername, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2)) return False; if(!prs_align(ps)) return False; - if(!prs_uint32("ptr_qual_name", ps, depth, &q_n->ptr_qual_name)) - return False; - if(!smb_io_unistr2("", &q_n->uni_qual_name, q_n->ptr_qual_name, ps, depth)) + if(!prs_pointer("qualifier", ps, depth, (void**)&q_u->qualifier, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2)) return False; if(!prs_align(ps)) return False; - if(!prs_uint32("ptr_user_name", ps, depth, &q_n->ptr_user_name)) - return False; - if(!smb_io_unistr2("", &q_n->uni_user_name, q_n->ptr_user_name, ps, depth)) + + if(!prs_pointer("username", ps, depth, (void**)&q_u->username, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2)) return False; if(!prs_align(ps)) return False; - if(!prs_uint32("sess_level", ps, depth, &q_n->sess_level)) + if(!prs_uint32("sess_level", ps, depth, &q_u->sess_level)) return False; - if (q_n->sess_level != (uint32)-1) { - if(!srv_io_srv_sess_ctr("sess_ctr", &q_n->ctr, ps, depth)) + if (q_u->sess_level != (uint32)-1) { + if(!srv_io_srv_sess_ctr("sess_ctr", &q_u->ctr, ps, depth)) return False; } - if(!prs_uint32("preferred_len", ps, depth, &q_n->preferred_len)) + if(!prs_uint32("preferred_len", ps, depth, &q_u->preferred_len)) return False; - if(!smb_io_enum_hnd("enum_hnd", &q_n->enum_hnd, ps, depth)) + if(!smb_io_enum_hnd("enum_hnd", &q_u->enum_hnd, ps, depth)) return False; return True; @@ -2434,22 +2327,10 @@ BOOL srv_io_r_net_conn_enum(const char *desc, SRV_R_NET_CONN_ENUM *r_n, prs_str } /******************************************************************* - Inits a FILE_INFO_3_STR structure -********************************************************************/ - -void init_srv_file_info3_str(FILE_INFO_3_STR *fi3, const char *user_name, const char *path_name) -{ - DEBUG(5,("init_srv_file_info3_str\n")); - - init_unistr2(&fi3->uni_path_name, path_name, UNI_STR_TERMINATE); - init_unistr2(&fi3->uni_user_name, user_name, UNI_STR_TERMINATE); -} - -/******************************************************************* Reads or writes a structure. ********************************************************************/ -static BOOL srv_io_file_info3_str(const char *desc, FILE_INFO_3_STR *sh1, prs_struct *ps, int depth) +static BOOL srv_io_file_info3_str(const char *desc, FILE_INFO_3 *sh1, prs_struct *ps, int depth) { if (sh1 == NULL) return False; @@ -2460,10 +2341,15 @@ static BOOL srv_io_file_info3_str(const char *desc, FILE_INFO_3_STR *sh1, prs_st if(!prs_align(ps)) return False; - if(!smb_io_unistr2("", &sh1->uni_path_name, True, ps, depth)) - return False; - if(!smb_io_unistr2("", &sh1->uni_user_name, True, ps, depth)) - return False; + if ( sh1->path ) { + if(!smb_io_unistr2("", sh1->path, True, ps, depth)) + return False; + } + + if ( sh1->user ) { + if(!smb_io_unistr2("", sh1->user, True, ps, depth)) + return False; + } return True; } @@ -2472,18 +2358,26 @@ static BOOL srv_io_file_info3_str(const char *desc, FILE_INFO_3_STR *sh1, prs_st Inits a FILE_INFO_3 structure ********************************************************************/ -void init_srv_file_info3(FILE_INFO_3 *fl3, - uint32 id, uint32 perms, uint32 num_locks, - const char *path_name, const char *user_name) +void init_srv_file_info3( FILE_INFO_3 *fl3, uint32 id, uint32 perms, uint32 num_locks, + const char *user_name, const char *path_name ) { - DEBUG(5,("init_srv_file_info3: %s %s\n", path_name, user_name)); - fl3->id = id; fl3->perms = perms; fl3->num_locks = num_locks; - fl3->ptr_path_name = (path_name != NULL) ? 1 : 0; - fl3->ptr_user_name = (user_name != NULL) ? 1 : 0; + if ( path_name ) { + if ( (fl3->path = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) + return; + init_unistr2(fl3->path, path_name, UNI_STR_TERMINATE); + } + + if ( user_name ) { + if ( (fl3->user = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) + return; + init_unistr2(fl3->user, user_name, UNI_STR_TERMINATE); + } + + return; } /******************************************************************* @@ -2492,6 +2386,8 @@ void init_srv_file_info3(FILE_INFO_3 *fl3, static BOOL srv_io_file_info3(const char *desc, FILE_INFO_3 *fl3, prs_struct *ps, int depth) { + uint32 uni_p; + if (fl3 == NULL) return False; @@ -2507,10 +2403,24 @@ static BOOL srv_io_file_info3(const char *desc, FILE_INFO_3 *fl3, prs_struct *ps return False; if(!prs_uint32("num_locks ", ps, depth, &fl3->num_locks)) return False; - if(!prs_uint32("ptr_path_name", ps, depth, &fl3->ptr_path_name)) + + uni_p = fl3->path ? (uint32)fl3->path : 0; + if(!prs_uint32("ptr", ps, depth, &uni_p)) return False; - if(!prs_uint32("ptr_user_name", ps, depth, &fl3->ptr_user_name)) + if (UNMARSHALLING(ps)) { + if ( (fl3->path = PRS_ALLOC_MEM( ps, UNISTR2, 1)) == NULL ) { + return False; + } + } + + uni_p = fl3->user ? (uint32)fl3->user : 0; + if(!prs_uint32("ptr", ps, depth, &uni_p)) return False; + if (UNMARSHALLING(ps)) { + if ( (fl3->user = PRS_ALLOC_MEM( ps, UNISTR2, 1)) == NULL ) { + return False; + } + } return True; } @@ -2528,55 +2438,53 @@ static BOOL srv_io_srv_file_ctr(const char *desc, SRV_FILE_INFO_CTR *ctr, prs_st depth++; if (UNMARSHALLING(ps)) { - memset(ctr, '\0', sizeof(SRV_FILE_INFO_CTR)); + ZERO_STRUCTP(ctr); } if(!prs_align(ps)) return False; - if(!prs_uint32("switch_value", ps, depth, &ctr->switch_value)) + if(!prs_uint32("level", ps, depth, &ctr->level)) return False; - if (ctr->switch_value != 3) { - DEBUG(5,("%s File info %d level not supported\n", - tab_depth(depth), ctr->switch_value)); - } + if(!prs_uint32("ptr_file_info", ps, depth, &ctr->ptr_file_info)) return False; if(!prs_uint32("num_entries", ps, depth, &ctr->num_entries)) return False; if(!prs_uint32("ptr_entries", ps, depth, &ctr->ptr_entries)) return False; + if (ctr->ptr_entries == 0) return True; - if(!prs_uint32("num_entries2", ps, depth, - &ctr->num_entries2)) + + if(!prs_uint32("num_entries2", ps, depth, &ctr->num_entries2)) return False; - switch (ctr->switch_value) { + switch (ctr->level) { case 3: { - SRV_FILE_INFO_3 *info3 = ctr->file.info3; + FILE_INFO_3 *info3 = ctr->file.info3; int num_entries = ctr->num_entries; int i; if (UNMARSHALLING(ps)) { - if (!(info3 = PRS_ALLOC_MEM(ps, SRV_FILE_INFO_3, num_entries))) + if (!(info3 = PRS_ALLOC_MEM(ps, FILE_INFO_3, num_entries))) return False; ctr->file.info3 = info3; } for (i = 0; i < num_entries; i++) { - if(!srv_io_file_info3("", &ctr->file.info3[i].info_3, ps, depth)) + if(!srv_io_file_info3("", &ctr->file.info3[i], ps, depth)) return False; } + for (i = 0; i < num_entries; i++) { - if(!srv_io_file_info3_str("", &ctr->file.info3[i].info_3_str, ps, depth)) + if(!srv_io_file_info3_str("", &ctr->file.info3[i], ps, depth)) return False; } break; } default: - DEBUG(5,("%s no file info at switch_value %d\n", - tab_depth(depth), ctr->switch_value)); + DEBUG(5,("%s no file info at switch_value %d\n", tab_depth(depth), ctr->level)); break; } @@ -2594,13 +2502,28 @@ void init_srv_q_net_file_enum(SRV_Q_NET_FILE_ENUM *q_n, uint32 preferred_len, ENUM_HND *hnd) { - DEBUG(5,("init_q_net_file_enum\n")); + uint32 ptr; - init_buf_unistr2(&q_n->uni_srv_name, &q_n->ptr_srv_name, srv_name); - init_buf_unistr2(&q_n->uni_qual_name, &q_n->ptr_qual_name, qual_name); - init_buf_unistr2(&q_n->uni_user_name, &q_n->ptr_user_name, user_name); + if ( srv_name ) { + if ( (q_n->servername = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) + return; + init_buf_unistr2(q_n->servername, &ptr, srv_name); + } + + if ( qual_name ) { + if ( (q_n->qualifier = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) + return; + init_buf_unistr2(q_n->qualifier, &ptr, qual_name); + } + + if ( user_name ) { + if ( (q_n->username = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) + return; + init_buf_unistr2(q_n->username, &ptr, user_name); + } + + q_n->level = q_n->ctr.level = file_level; - q_n->file_level = q_n->ctr.switch_value = file_level; q_n->preferred_len = preferred_len; q_n->ctr.ptr_file_info = 1; q_n->ctr.num_entries = 0; @@ -2613,9 +2536,9 @@ void init_srv_q_net_file_enum(SRV_Q_NET_FILE_ENUM *q_n, Reads or writes a structure. ********************************************************************/ -BOOL srv_io_q_net_file_enum(const char *desc, SRV_Q_NET_FILE_ENUM *q_n, prs_struct *ps, int depth) +BOOL srv_io_q_net_file_enum(const char *desc, SRV_Q_NET_FILE_ENUM *q_u, prs_struct *ps, int depth) { - if (q_n == NULL) + if (q_u == NULL) return False; prs_debug(ps, depth, desc, "srv_io_q_net_file_enum"); @@ -2624,41 +2547,33 @@ BOOL srv_io_q_net_file_enum(const char *desc, SRV_Q_NET_FILE_ENUM *q_n, prs_stru if(!prs_align(ps)) return False; - if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name)) + if(!prs_pointer("servername", ps, depth, (void**)&q_u->servername, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2)) return False; - if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth)) - return False; - if(!prs_align(ps)) return False; - if(!prs_uint32("ptr_qual_name", ps, depth, &q_n->ptr_qual_name)) - return False; - if(!smb_io_unistr2("", &q_n->uni_qual_name, q_n->ptr_qual_name, ps, depth)) + if(!prs_pointer("qualifier", ps, depth, (void**)&q_u->qualifier, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2)) return False; - if(!prs_align(ps)) return False; - if(!prs_uint32("ptr_user_name", ps, depth, &q_n->ptr_user_name)) - return False; - if(!smb_io_unistr2("", &q_n->uni_user_name, q_n->ptr_user_name, ps, depth)) + if(!prs_pointer("username", ps, depth, (void**)&q_u->username, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2)) return False; - if(!prs_align(ps)) return False; - if(!prs_uint32("file_level", ps, depth, &q_n->file_level)) + + if(!prs_uint32("level", ps, depth, &q_u->level)) return False; - if (q_n->file_level != (uint32)-1) { - if(!srv_io_srv_file_ctr("file_ctr", &q_n->ctr, ps, depth)) + if (q_u->level != (uint32)-1) { + if(!srv_io_srv_file_ctr("file_ctr", &q_u->ctr, ps, depth)) return False; } - if(!prs_uint32("preferred_len", ps, depth, &q_n->preferred_len)) + if(!prs_uint32("preferred_len", ps, depth, &q_u->preferred_len)) return False; - if(!smb_io_enum_hnd("enum_hnd", &q_n->enum_hnd, ps, depth)) + if(!smb_io_enum_hnd("enum_hnd", &q_u->enum_hnd, ps, depth)) return False; return True; @@ -2679,10 +2594,10 @@ BOOL srv_io_r_net_file_enum(const char *desc, SRV_R_NET_FILE_ENUM *r_n, prs_stru if(!prs_align(ps)) return False; - if(!prs_uint32("file_level", ps, depth, &r_n->file_level)) + if(!prs_uint32("level", ps, depth, &r_n->level)) return False; - if (r_n->file_level != 0) { + if (r_n->level != 0) { if(!srv_io_srv_file_ctr("file_ctr", &r_n->ctr, ps, depth)) return False; } @@ -2703,63 +2618,17 @@ BOOL srv_io_r_net_file_enum(const char *desc, SRV_R_NET_FILE_ENUM *r_n, prs_stru void init_srv_q_net_file_close(SRV_Q_NET_FILE_CLOSE *q_n, const char *server, uint32 file_id) { - q_n->ptr_srv_name = 1; - init_unistr2(&q_n->uni_srv_name, server, UNI_STR_TERMINATE); - q_n->file_id = file_id; -} - -/******************************************************************* - Reads or writes a structure. -********************************************************************/ -BOOL srv_io_q_net_file_close(const char *desc, SRV_Q_NET_FILE_CLOSE *q_n, - prs_struct *ps, int depth) -{ - if (q_n == NULL) - return False; - - prs_debug(ps, depth, desc, "srv_io_q_net_file_close"); - depth++; - - if(!prs_align(ps)) - return False; - - if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name)) - return False; - if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth)) - return False; - - if(!prs_align(ps)) - return False; - - if(!prs_uint32("file_id", ps, depth, &q_n->file_id)) - return False; + if ( server ) { + if ( (q_n->servername = TALLOC_P( get_talloc_ctx(), UNISTR2 )) == NULL ) { + return; + } + init_unistr2(q_n->servername, server, UNI_STR_TERMINATE); + } - return True; + q_n->file_id = file_id; } /******************************************************************* - Reads or writes a structure. -********************************************************************/ - -BOOL srv_io_r_net_file_close(const char *desc, SRV_R_NET_FILE_CLOSE *q_n, - prs_struct *ps, int depth) -{ - if (q_n == NULL) - return False; - - prs_debug(ps, depth, desc, "srv_io_r_net_file_close"); - depth++; - - if(!prs_align(ps)) - return False; - - if(!prs_werror("status", ps, depth, &q_n->status)) - return False; - - return True; -} - -/******************************************************************* Inits a SRV_INFO_100 structure. ********************************************************************/ @@ -3411,25 +3280,6 @@ BOOL srv_io_r_net_disk_enum(const char *desc, SRV_R_NET_DISK_ENUM *r_n, prs_stru } /******************************************************************* - initialises a structure. - ********************************************************************/ - -BOOL init_srv_q_net_name_validate(SRV_Q_NET_NAME_VALIDATE *q_n, const char *srv_name, const char *share_name, int type) -{ - uint32 ptr_share_name; - - DEBUG(5,("init_srv_q_net_name_validate\n")); - - init_buf_unistr2(&q_n->uni_srv_name, &q_n->ptr_srv_name, srv_name); - init_buf_unistr2(&q_n->uni_name, &ptr_share_name, share_name); - - q_n->type = type; - q_n->flags = 0; - - return True; -} - -/******************************************************************* Reads or writes a structure. ********************************************************************/ @@ -3444,16 +3294,13 @@ BOOL srv_io_q_net_name_validate(const char *desc, SRV_Q_NET_NAME_VALIDATE *q_n, if(!prs_align(ps)) return False; - if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name)) - return False; - - if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth)) + if(!prs_pointer("servername", ps, depth, (void**)&q_n->servername, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2)) return False; if(!prs_align(ps)) return False; - if(!smb_io_unistr2("", &q_n->uni_name, True, ps, depth)) + if(!smb_io_unistr2("", &q_n->sharename, True, ps, depth)) return False; if(!prs_align(ps)) @@ -3663,3 +3510,48 @@ void init_srv_q_net_remote_tod(SRV_Q_NET_REMOTE_TOD *q_u, const char *server) q_u->ptr_srv_name = 1; init_unistr2(&q_u->uni_srv_name, server, UNI_STR_TERMINATE); } + + +/******************************************************************* + Reads or writes a structure. +********************************************************************/ + +BOOL srv_io_q_net_file_close(const char *desc, SRV_Q_NET_FILE_CLOSE *q_u, prs_struct *ps, int depth) +{ + if (q_u == NULL) + return False; + + prs_debug(ps, depth, desc, "srv_io_q_net_file_close"); + depth++; + + if(!prs_align(ps)) + return False; + + if(!prs_pointer("servername", ps, depth, (void**)&q_u->servername, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2)) + return False; + if(!prs_align(ps)) + return False; + + if(!prs_uint32("file_id", ps, depth, &q_u->file_id)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +BOOL srv_io_r_net_file_close(const char *desc, SRV_R_NET_FILE_CLOSE *r_n, + prs_struct *ps, int depth) +{ + prs_debug(ps, depth, desc, "srv_io_r_net_file_close"); + depth++; + + if(!prs_align(ps)) + return False; + + if(!prs_werror("status", ps, depth, &r_n->status)) + return False; + + return True; +} diff --git a/source/rpc_server/srv_dfs_nt.c b/source/rpc_server/srv_dfs_nt.c index 1a2ad38910a..e93b0077f0c 100644 --- a/source/rpc_server/srv_dfs_nt.c +++ b/source/rpc_server/srv_dfs_nt.c @@ -43,6 +43,8 @@ WERROR _dfs_Add(pipes_struct *p, NETDFS_Q_DFS_ADD* q_u, NETDFS_R_DFS_ADD *r_u) struct current_user user; struct junction_map jn; struct referral* old_referral_list = NULL; + BOOL self_ref = False; + int consumedcnt = 0; BOOL exists = False; pstring dfspath, servername, sharename; @@ -67,7 +69,7 @@ WERROR _dfs_Add(pipes_struct *p, NETDFS_Q_DFS_ADD* q_u, NETDFS_R_DFS_ADD *r_u) pstrcat(altpath, sharename); /* The following call can change the cwd. */ - if(get_referred_path(p->mem_ctx, dfspath, &jn, NULL, NULL)) { + if(get_referred_path(p->mem_ctx, dfspath, &jn, &consumedcnt, &self_ref)) { exists = True; jn.referral_count += 1; old_referral_list = jn.referral_list; @@ -106,6 +108,8 @@ WERROR _dfs_Remove(pipes_struct *p, NETDFS_Q_DFS_REMOVE *q_u, { struct current_user user; struct junction_map jn; + BOOL self_ref = False; + int consumedcnt = 0; BOOL found = False; pstring dfspath, servername, sharename; @@ -137,7 +141,7 @@ WERROR _dfs_Remove(pipes_struct *p, NETDFS_Q_DFS_REMOVE *q_u, DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n", dfspath, servername, sharename)); - if(!get_referred_path(p->mem_ctx, dfspath, &jn, NULL, NULL)) { + if(!get_referred_path(p->mem_ctx, dfspath, &jn, &consumedcnt, &self_ref)) { return WERR_DFS_NO_SUCH_VOL; } @@ -346,6 +350,7 @@ WERROR _dfs_GetInfo(pipes_struct *p, NETDFS_Q_DFS_GETINFO *q_u, int consumedcnt = sizeof(pstring); pstring path; BOOL ret = False; + BOOL self_ref = False; struct junction_map jn; unistr2_to_ascii(path, uni_path, sizeof(path)-1); @@ -353,7 +358,7 @@ WERROR _dfs_GetInfo(pipes_struct *p, NETDFS_Q_DFS_GETINFO *q_u, return WERR_DFS_NO_SUCH_SERVER; /* The following call can change the cwd. */ - if(!get_referred_path(p->mem_ctx, path, &jn, &consumedcnt, NULL) || consumedcnt < strlen(path)) { + if(!get_referred_path(p->mem_ctx, path, &jn, &consumedcnt, &self_ref) || consumedcnt < strlen(path)) { vfs_ChDir(p->conn,p->conn->connectpath); return WERR_DFS_NO_SUCH_VOL; } @@ -489,4 +494,3 @@ WERROR _dfs_SetInfo2(pipes_struct *p, NETDFS_Q_DFS_SETINFO2 *q_u, NETDFS_R_DFS_S /* FIXME: Implement your code here */ return WERR_NOT_SUPPORTED; } - diff --git a/source/rpc_server/srv_pipe_hnd.c b/source/rpc_server/srv_pipe_hnd.c index 9cc8b72546f..26e06f60a17 100644 --- a/source/rpc_server/srv_pipe_hnd.c +++ b/source/rpc_server/srv_pipe_hnd.c @@ -1169,6 +1169,13 @@ BOOL close_rpc_pipe_hnd(smb_np_struct *p) p->name, p->pnum, pipes_open)); DLIST_REMOVE(Pipes, p); + + /* Remove from pipe open db */ + + if ( !delete_pipe_opendb( p ) ) { + DEBUG(3,("close_rpc_pipe_hnd: failed to delete %s " + "pipe from open db.\n", p->name)); + } ZERO_STRUCTP(p); diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c index 07a89de5e61..0b2e24fa899 100644 --- a/source/rpc_server/srv_samr_nt.c +++ b/source/rpc_server/srv_samr_nt.c @@ -3886,7 +3886,7 @@ NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_ init_samr_r_query_aliasmem(r_u, num_sids, sid, NT_STATUS_OK); - SAFE_FREE(sids); + TALLOC_FREE(sids); return NT_STATUS_OK; } diff --git a/source/rpc_server/srv_srvsvc.c b/source/rpc_server/srv_srvsvc.c index 0b4eac5cc73..e4f85d0bdb4 100644 --- a/source/rpc_server/srv_srvsvc.c +++ b/source/rpc_server/srv_srvsvc.c @@ -6,6 +6,7 @@ * Copyright (C) Paul Ashton 1997, * Copyright (C) Jeremy Allison 2001, * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003. + * Copyright (C) Gera;d (Jerry) Carter 2006. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -551,6 +552,35 @@ static BOOL api_srv_net_file_set_secdesc(pipes_struct *p) } /******************************************************************* +*******************************************************************/ + +static BOOL api_srv_net_file_close(pipes_struct *p) +{ + SRV_Q_NET_FILE_CLOSE q_u; + SRV_R_NET_FILE_CLOSE r_u; + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + /* Unmarshall the net file set info from Win9x */ + if(!srv_io_q_net_file_close("", &q_u, data, 0)) { + DEBUG(0,("api_srv_net_file_close: Failed to unmarshall SRV_Q_NET_FILE_SET_SECDESC.\n")); + return False; + } + + r_u.status = _srv_net_file_close(p, &q_u, &r_u); + + if(!srv_io_r_net_file_close("", &r_u, rdata, 0)) { + DEBUG(0,("api_srv_net_file_close: Failed to marshall SRV_R_NET_FILE_SET_SECDESC.\n")); + return False; + } + + return True; +} + +/******************************************************************* \PIPE\srvsvc commands ********************************************************************/ @@ -573,7 +603,8 @@ static struct api_struct api_srv_cmds[] = { "SRV_NET_DISK_ENUM" , SRV_NET_DISK_ENUM , api_srv_net_disk_enum }, { "SRV_NET_NAME_VALIDATE" , SRV_NET_NAME_VALIDATE , api_srv_net_name_validate }, { "SRV_NET_FILE_QUERY_SECDESC", SRV_NET_FILE_QUERY_SECDESC, api_srv_net_file_query_secdesc }, - { "SRV_NET_FILE_SET_SECDESC" , SRV_NET_FILE_SET_SECDESC , api_srv_net_file_set_secdesc } + { "SRV_NET_FILE_SET_SECDESC" , SRV_NET_FILE_SET_SECDESC , api_srv_net_file_set_secdesc }, + { "SRV_NET_FILE_CLOSE" , SRV_NET_FILE_CLOSE , api_srv_net_file_close } }; void srvsvc_get_pipe_fns( struct api_struct **fns, int *n_fns ) diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c index 06a8c77098d..d03ab66b50d 100644 --- a/source/rpc_server/srv_srvsvc_nt.c +++ b/source/rpc_server/srv_srvsvc_nt.c @@ -4,6 +4,7 @@ * Copyright (C) Andrew Tridgell 1992-1997, * Copyright (C) Jeremy Allison 2001. * Copyright (C) Nigel Williams 2001. + * Copyright (C) Gerald (Jerry) Carter 2006. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +30,174 @@ extern struct generic_mapping file_generic_mapping; #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV +/* Use for enumerating connections, pipes, & files */ + +struct file_enum_count { + TALLOC_CTX *ctx; + int count; + FILE_INFO_3 *info; +}; + +struct sess_file_count { + pid_t pid; + uid_t uid; + int count; +}; + +/**************************************************************************** + Count the entries belonging to a service in the connection db. +****************************************************************************/ + +static int pipe_enum_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *p) +{ + struct pipe_open_rec prec; + struct file_enum_count *fenum = (struct file_enum_count *)p; + + if (dbuf.dsize != sizeof(struct pipe_open_rec)) + return 0; + + memcpy(&prec, dbuf.dptr, sizeof(struct pipe_open_rec)); + + if ( process_exists(prec.pid) ) { + FILE_INFO_3 *f; + int i = fenum->count; + pstring fullpath; + + snprintf( fullpath, sizeof(fullpath), "\\PIPE\\%s", prec.name ); + + f = TALLOC_REALLOC_ARRAY( fenum->ctx, fenum->info, FILE_INFO_3, i+1 ); + if ( !f ) { + DEBUG(0,("conn_enum_fn: realloc failed for %d items\n", i+1)); + return 1; + } + fenum->info = f; + + + init_srv_file_info3( &fenum->info[i], + (uint32)((procid_to_pid(&prec.pid)<<16) & prec.pnum), + (FILE_READ_DATA|FILE_WRITE_DATA), + 0, + uidtoname( prec.uid ), + fullpath ); + + fenum->count++; + } + + return 0; +} + +/******************************************************************* +********************************************************************/ + +static WERROR net_enum_pipes( TALLOC_CTX *ctx, FILE_INFO_3 **info, + uint32 *count, uint32 resume ) +{ + struct file_enum_count fenum; + TDB_CONTEXT *conn_tdb = conn_tdb_ctx(); + + if ( !conn_tdb ) { + DEBUG(0,("net_enum_pipes: Failed to retrieve the connections tdb handle!\n")); + return WERR_ACCESS_DENIED; + } + + fenum.ctx = ctx; + fenum.count = *count; + fenum.info = *info; + + if (tdb_traverse(conn_tdb, pipe_enum_fn, &fenum) == -1) { + DEBUG(0,("net_enum_pipes: traverse of connections.tdb failed with error %s.\n", + tdb_errorstr(conn_tdb) )); + return WERR_NOMEM; + } + + *info = fenum.info; + *count = fenum.count; + + return WERR_OK;} + +/******************************************************************* +********************************************************************/ + +/* global needed to make use of the share_mode_forall() callback */ +static struct file_enum_count f_enum_cnt; + +static void enum_file_fn( const struct share_mode_entry *e, + const char *sharepath, const char *fname, void *state ) +{ + struct file_enum_count *fenum = &f_enum_cnt; + + /* If the pid was not found delete the entry from connections.tdb */ + + if ( process_exists(e->pid) ) { + FILE_INFO_3 *f; + int i = fenum->count; + files_struct fsp; + struct byte_range_lock *brl; + int num_locks = 0; + pstring fullpath; + uint32 permissions; + + f = TALLOC_REALLOC_ARRAY( fenum->ctx, fenum->info, FILE_INFO_3, i+1 ); + if ( !f ) { + DEBUG(0,("conn_enum_fn: realloc failed for %d items\n", i+1)); + return; + } + fenum->info = f; + + /* need to count the number of locks on a file */ + + ZERO_STRUCT( fsp ); + fsp.dev = e->dev; + fsp.inode = e->inode; + + if ( (brl = brl_get_locks(NULL,&fsp)) != NULL ) { + num_locks = brl->num_locks; + TALLOC_FREE( brl ); + } + + if ( strcmp( fname, "." ) == 0 ) { + pstr_sprintf( fullpath, "C:%s", sharepath ); + } else { + pstr_sprintf( fullpath, "C:%s/%s", sharepath, fname ); + } + string_replace( fullpath, '/', '\\' ); + + /* mask out create (what ever that is) */ + permissions = e->share_access & (FILE_READ_DATA|FILE_WRITE_DATA); + + /* now fill in the FILE_INFO_3 struct */ + init_srv_file_info3( &fenum->info[i], + e->share_file_id, + permissions, + num_locks, + uidtoname(e->uid), + fullpath ); + + fenum->count++; + } + + return; + +} + +/******************************************************************* +********************************************************************/ + +static WERROR net_enum_files( TALLOC_CTX *ctx, FILE_INFO_3 **info, + uint32 *count, uint32 resume ) +{ + f_enum_cnt.ctx = ctx; + f_enum_cnt.count = *count; + f_enum_cnt.info = *info; + + share_mode_forall( enum_file_fn, NULL ); + + *info = f_enum_cnt.info; + *count = f_enum_cnt.count; + + return WERR_OK; +} + /******************************************************************* Utility function to get the 'type' of a share from an snum. ********************************************************************/ @@ -91,8 +260,9 @@ static void init_srv_share_info_2(pipes_struct *p, SRV_SHARE_INFO_2 *sh2, int sn pstring passwd; int max_connections = lp_max_connections(snum); uint32 max_uses = max_connections!=0 ? max_connections : 0xffffffff; - + int count = 0; char *net_name = lp_servicename(snum); + pstrcpy(remark, lp_comment(snum)); standard_sub_conn(p->conn, remark,sizeof(remark)); pstrcpy(path, "C:"); @@ -107,7 +277,10 @@ static void init_srv_share_info_2(pipes_struct *p, SRV_SHARE_INFO_2 *sh2, int sn pstrcpy(passwd, ""); - init_srv_share_info2(&sh2->info_2, net_name, get_share_type(snum), remark, 0, max_uses, 1, path, passwd); + count = count_current_connections( net_name, False ); + init_srv_share_info2(&sh2->info_2, net_name, get_share_type(snum), + remark, 0, max_uses, count, path, passwd); + init_srv_share_info2_str(&sh2->info_2_str, net_name, remark, path, passwd); } @@ -596,16 +769,6 @@ static void init_srv_r_net_share_get_info(pipes_struct *p, SRV_R_NET_SHARE_GET_I } /******************************************************************* - fill in a sess info level 1 structure. - ********************************************************************/ - -static void init_srv_sess_0_info(SESS_INFO_0 *se0, SESS_INFO_0_STR *str0, char *name) -{ - init_srv_sess_info0(se0, name); - init_srv_sess_info0_str(str0, name); -} - -/******************************************************************* fill in a sess info level 0 structure. ********************************************************************/ @@ -627,11 +790,7 @@ static void init_srv_sess_info_0(SRV_SESS_INFO_0 *ss0, uint32 *snum, uint32 *sto if (snum) { for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++) { - init_srv_sess_0_info(&ss0->info_0[num_entries], - &ss0->info_0_str[num_entries], session_list[(*snum)].remote_machine); - - /* move on to creating next session */ - /* move on to creating next sess */ + init_srv_sess_info0( &ss0->info_0[num_entries], session_list[(*snum)].remote_machine); num_entries++; } @@ -652,17 +811,35 @@ static void init_srv_sess_info_0(SRV_SESS_INFO_0 *ss0, uint32 *snum, uint32 *sto } /******************************************************************* - fill in a sess info level 1 structure. - ********************************************************************/ +********************************************************************/ + +/* global needed to make use of the share_mode_forall() callback */ +static struct sess_file_count s_file_cnt; + +static void sess_file_fn( const struct share_mode_entry *e, + const char *sharepath, const char *fname, void *state ) +{ + struct sess_file_count *sess = &s_file_cnt; + + if ( (procid_to_pid(&e->pid) == sess->pid) && (sess->uid == e->uid) ) { + sess->count++; + } + + return; +} -static void init_srv_sess_1_info(SESS_INFO_1 *se1, SESS_INFO_1_STR *str1, - char *name, char *user, - uint32 num_opens, - uint32 open_time, uint32 idle_time, - uint32 usr_flgs) +/******************************************************************* +********************************************************************/ + +static int net_count_files( uid_t uid, pid_t pid ) { - init_srv_sess_info1(se1 , name, user, num_opens, open_time, idle_time, usr_flgs); - init_srv_sess_info1_str(str1, name, user); + s_file_cnt.count = 0; + s_file_cnt.uid = uid; + s_file_cnt.pid = pid; + + share_mode_forall( sess_file_fn, NULL ); + + return s_file_cnt.count; } /******************************************************************* @@ -673,43 +850,58 @@ static void init_srv_sess_info_1(SRV_SESS_INFO_1 *ss1, uint32 *snum, uint32 *sto { struct sessionid *session_list; uint32 num_entries = 0; - (*stot) = list_sessions(&session_list); + time_t now = time(NULL); + if ( !snum ) { + ss1->num_entries_read = 0; + ss1->ptr_sess_info = 0; + ss1->num_entries_read2 = 0; + + (*stot) = 0; + + return; + } + if (ss1 == NULL) { (*snum) = 0; - SAFE_FREE(session_list); return; } - DEBUG(5,("init_srv_sess_1_ss1\n")); - - if (snum) { - for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++) { - init_srv_sess_1_info(&ss1->info_1[num_entries], - &ss1->info_1_str[num_entries], - session_list[*snum].remote_machine, - session_list[*snum].username, - 1, 10, 5, 0); - - /* move on to creating next session */ - /* move on to creating next sess */ - num_entries++; - } + (*stot) = list_sessions(&session_list); + - ss1->num_entries_read = num_entries; - ss1->ptr_sess_info = num_entries > 0 ? 1 : 0; - ss1->num_entries_read2 = num_entries; - - if ((*snum) >= (*stot)) { - (*snum) = 0; + for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++) { + uint32 num_files; + uint32 connect_time; + struct passwd *pw = sys_getpwnam(session_list[*snum].username); + BOOL guest; + + if ( !pw ) { + DEBUG(10,("init_srv_sess_info_1: failed to find owner: %s\n", + session_list[*snum].username)); + continue; } - - } else { - ss1->num_entries_read = 0; - ss1->ptr_sess_info = 0; - ss1->num_entries_read2 = 0; - - (*stot) = 0; + + connect_time = (uint32)(now - session_list[*snum].connect_start); + num_files = net_count_files(pw->pw_uid, session_list[*snum].pid); + guest = strequal( session_list[*snum].username, lp_guestaccount() ); + + init_srv_sess_info1( &ss1->info_1[num_entries], + session_list[*snum].remote_machine, + session_list[*snum].username, + num_files, + connect_time, + 0, + guest); + num_entries++; + } + + ss1->num_entries_read = num_entries; + ss1->ptr_sess_info = num_entries > 0 ? 1 : 0; + ss1->num_entries_read2 = num_entries; + + if ((*snum) >= (*stot)) { + (*snum) = 0; } SAFE_FREE(session_list); @@ -929,66 +1121,53 @@ static void init_srv_r_net_conn_enum(SRV_R_NET_CONN_ENUM *r_n, makes a SRV_R_NET_FILE_ENUM structure. ********************************************************************/ -static WERROR init_srv_file_info_ctr(pipes_struct *p, SRV_FILE_INFO_CTR *ctr, - int switch_value, uint32 *resume_hnd, - uint32 *total_entries) +static WERROR net_file_enum_3( SRV_R_NET_FILE_ENUM *r, uint32 resume_hnd ) { - WERROR status = WERR_OK; - TALLOC_CTX *ctx = p->mem_ctx; - DEBUG(5,("init_srv_file_info_ctr: %d\n", __LINE__)); - *total_entries = 1; /* dummy entries only, for */ + TALLOC_CTX *ctx = get_talloc_ctx(); + SRV_FILE_INFO_CTR *ctr = &r->ctr; - ctr->switch_value = switch_value; - ctr->num_entries = *total_entries - *resume_hnd; + /* TODO -- Windows enumerates + (b) active pipes + (c) open directories and files */ + + r->status = net_enum_files( ctx, &ctr->file.info3, &ctr->num_entries, resume_hnd ); + if ( !W_ERROR_IS_OK(r->status)) + goto done; + + r->status = net_enum_pipes( ctx, &ctr->file.info3, &ctr->num_entries, resume_hnd ); + if ( !W_ERROR_IS_OK(r->status)) + goto done; + + r->level = ctr->level = 3; + r->total_entries = ctr->num_entries; + /* ctr->num_entries = r->total_entries - resume_hnd; */ ctr->num_entries2 = ctr->num_entries; + ctr->ptr_file_info = 1; - switch (switch_value) { - case 3: { - int i; - if (*total_entries > 0) { - ctr->ptr_entries = 1; - ctr->file.info3 = TALLOC_ARRAY(ctx, SRV_FILE_INFO_3, ctr->num_entries); - } - for (i=0 ;i<ctr->num_entries;i++) { - init_srv_file_info3(&ctr->file.info3[i].info_3, i+*resume_hnd, 0x35, 0, "\\PIPE\\samr", "dummy user"); - init_srv_file_info3_str(&ctr->file.info3[i].info_3_str, "\\PIPE\\samr", "dummy user"); - - } - ctr->ptr_file_info = 1; - *resume_hnd = 0; - break; - } - default: - DEBUG(5,("init_srv_file_info_ctr: unsupported switch value %d\n", switch_value)); - (*resume_hnd = 0); - (*total_entries) = 0; - ctr->ptr_entries = 0; - status = WERR_UNKNOWN_LEVEL; - break; - } + r->status = WERR_OK; - return status; +done: + if ( ctr->num_entries > 0 ) + ctr->ptr_entries = 1; + + init_enum_hnd(&r->enum_hnd, 0); + + return r->status; } /******************************************************************* - makes a SRV_R_NET_FILE_ENUM structure. -********************************************************************/ +*******************************************************************/ -static void init_srv_r_net_file_enum(pipes_struct *p, SRV_R_NET_FILE_ENUM *r_n, - uint32 resume_hnd, int file_level, int switch_value) +WERROR _srv_net_file_enum(pipes_struct *p, SRV_Q_NET_FILE_ENUM *q_u, SRV_R_NET_FILE_ENUM *r_u) { - DEBUG(5,("init_srv_r_net_file_enum: %d\n", __LINE__)); - - r_n->file_level = file_level; - if (file_level == 0) - r_n->status = WERR_UNKNOWN_LEVEL; - else - r_n->status = init_srv_file_info_ctr(p, &r_n->ctr, switch_value, &resume_hnd, &(r_n->total_entries)); - - if (!W_ERROR_IS_OK(r_n->status)) - resume_hnd = 0; - - init_enum_hnd(&r_n->enum_hnd, resume_hnd); + switch ( q_u->level ) { + case 3: + return net_file_enum_3( r_u, get_enum_hnd(&q_u->enum_hnd) ); + default: + return WERR_UNKNOWN_LEVEL; + } + + return WERR_OK; } /******************************************************************* @@ -1075,25 +1254,6 @@ WERROR _srv_net_srv_set_info(pipes_struct *p, SRV_Q_NET_SRV_SET_INFO *q_u, SRV_R } /******************************************************************* -net file enum -********************************************************************/ - -WERROR _srv_net_file_enum(pipes_struct *p, SRV_Q_NET_FILE_ENUM *q_u, SRV_R_NET_FILE_ENUM *r_u) -{ - DEBUG(5,("srv_net_file_enum: %d\n", __LINE__)); - - /* set up the */ - init_srv_r_net_file_enum(p, r_u, - get_enum_hnd(&q_u->enum_hnd), - q_u->file_level, - q_u->ctr.switch_value); - - DEBUG(5,("srv_net_file_enum: %d\n", __LINE__)); - - return r_u->status; -} - -/******************************************************************* net conn enum ********************************************************************/ @@ -2102,7 +2262,7 @@ WERROR _srv_net_name_validate(pipes_struct *p, SRV_Q_NET_NAME_VALIDATE *q_u, SRV switch ( q_u->type ) { case 0x9: - rpcstr_pull(sharename, q_u->uni_name.buffer, sizeof(sharename), q_u->uni_name.uni_str_len*2, 0); + rpcstr_pull(sharename, q_u->sharename.buffer, sizeof(sharename), q_u->sharename.uni_str_len*2, 0); if ( !validate_net_name( sharename, INVALID_SHARENAME_CHARS, sizeof(sharename) ) ) { DEBUG(5,("_srv_net_name_validate: Bad sharename \"%s\"\n", sharename)); return WERR_INVALID_NAME; @@ -2115,3 +2275,13 @@ WERROR _srv_net_name_validate(pipes_struct *p, SRV_Q_NET_NAME_VALIDATE *q_u, SRV return WERR_OK; } + + +/******************************************************************** +********************************************************************/ + +WERROR _srv_net_file_close(pipes_struct *p, SRV_Q_NET_FILE_CLOSE *q_u, SRV_R_NET_FILE_CLOSE *r_u) +{ + return WERR_ACCESS_DENIED; +} + diff --git a/source/rpcclient/cmd_samr.c b/source/rpcclient/cmd_samr.c index e2a026c87bf..676d84835de 100644 --- a/source/rpcclient/cmd_samr.c +++ b/source/rpcclient/cmd_samr.c @@ -1858,6 +1858,7 @@ static NTSTATUS cmd_samr_query_sec_obj(struct rpc_pipe_client *cli, if ((argc < 1) || (argc > 3)) { printf("Usage: %s [rid|-d] [sec_info]\n", argv[0]); printf("\tSpecify rid for security on user, -d for security on domain\n"); + talloc_destroy(ctx); return NT_STATUS_OK; } diff --git a/source/smbd/close.c b/source/smbd/close.c index b826cd622af..a123a542fd2 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -373,9 +373,9 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_ * Ensure pending modtime is set after close. */ - if(fsp->pending_modtime && fsp->pending_modtime_owner) { + if (fsp->pending_modtime_owner && !null_timespec(fsp->pending_modtime)) { set_filetime(conn, fsp->fsp_name, fsp->pending_modtime); - } else if (fsp->last_write_time) { + } else if (!null_timespec(fsp->last_write_time)) { set_filetime(conn, fsp->fsp_name, fsp->last_write_time); } diff --git a/source/smbd/dir.c b/source/smbd/dir.c index 2795b2a24b2..db3e155ae47 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -1017,6 +1017,7 @@ BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char * } if (hide_unreadable || hide_unwriteable || hide_special) { + pstring link_target; char *entry = NULL; if (asprintf(&entry, "%s/%s", dir_path, name) == -1) { @@ -1026,10 +1027,7 @@ BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char * /* If it's a dfs symlink, ignore _hide xxxx_ options */ if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) && - /* We get away with NULL talloc ctx here as - we're not interested in the link contents - so we have nothing to free. */ - is_msdfs_link(NULL, conn, entry, NULL, NULL, NULL)) { + is_msdfs_link(conn, entry, link_target, NULL)) { SAFE_FREE(entry); return True; } diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index ad79bbacddf..71d4fa179d4 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -282,7 +282,7 @@ static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_ } /* We want DOS semantics, ie allow non owner with write permission to change the - bits on a file. Just like file_utime below. + bits on a file. Just like file_ntimes below. */ /* Check if we have write access. */ @@ -504,7 +504,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, return -1; /* We want DOS semantics, ie allow non owner with write permission to change the - bits on a file. Just like file_utime below. + bits on a file. Just like file_ntimes below. */ /* Check if we have write access. */ @@ -532,11 +532,11 @@ int file_set_dosmode(connection_struct *conn, const char *fname, } /******************************************************************* - Wrapper around dos_utime that possibly allows DOS semantics rather + Wrapper around the VFS ntimes that possibly allows DOS semantics rather than POSIX. *******************************************************************/ -int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times) +int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2]) { SMB_STRUCT_STAT sbuf; int ret = -1; @@ -555,14 +555,17 @@ int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times return 0; } - if(SMB_VFS_UTIME(conn,fname, times) == 0) + if(SMB_VFS_NTIMES(conn, fname, ts) == 0) { return 0; + } - if((errno != EPERM) && (errno != EACCES)) + if((errno != EPERM) && (errno != EACCES)) { return -1; + } - if(!lp_dos_filetimes(SNUM(conn))) + if(!lp_dos_filetimes(SNUM(conn))) { return -1; + } /* We have permission (given by the Samba admin) to break POSIX semantics and allow a user to change @@ -574,7 +577,7 @@ int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times if (can_write_to_file(conn, fname, &sbuf)) { /* We are allowed to become root and change the filetime. */ become_root(); - ret = SMB_VFS_UTIME(conn,fname, times); + ret = SMB_VFS_NTIMES(conn, fname, ts); unbecome_root(); } @@ -585,16 +588,19 @@ int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times Change a filetime - possibly allowing DOS semantics. *******************************************************************/ -BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime) +BOOL set_filetime(connection_struct *conn, const char *fname, + const struct timespec mtime) { - struct utimbuf times; + struct timespec ts[2]; - if (null_mtime(mtime)) + if (null_timespec(mtime)) { return(True); + } - times.modtime = times.actime = mtime; + ts[1] = mtime; /* mtime. */ + ts[0] = ts[1]; /* atime. */ - if (file_utime(conn, fname, ×)) { + if (file_ntimes(conn, fname, ts)) { DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno))); return False; } @@ -602,5 +608,5 @@ BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime) notify_fname(conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_LAST_WRITE, fname); - return(True); -} + return True; +} diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index e0945be8893..65238c0e9ee 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -149,13 +149,13 @@ static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos * The 99% solution will hopefully be good enough in this case. JRA. */ - if (fsp->pending_modtime) { + if (!null_timespec(fsp->pending_modtime)) { set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime); /* If we didn't get the "set modtime" call ourselves, we must store the last write time to restore on close. JRA. */ if (!fsp->pending_modtime_owner) { - fsp->last_write_time = time(NULL); + fsp->last_write_time = timespec_current(); } } diff --git a/source/smbd/files.c b/source/smbd/files.c index 66ef37bb0fa..23fd47671b8 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -383,11 +383,11 @@ files_struct *file_find_print(void) Record the owner of that modtime. ****************************************************************************/ -void fsp_set_pending_modtime(files_struct *tfsp, time_t pmod) +void fsp_set_pending_modtime(files_struct *tfsp, const struct timespec mod) { files_struct *fsp; - if (null_mtime(pmod)) { + if (null_timespec(mod)) { return; } @@ -395,7 +395,7 @@ void fsp_set_pending_modtime(files_struct *tfsp, time_t pmod) if ( fsp->fh->fd != -1 && fsp->dev == tfsp->dev && fsp->inode == tfsp->inode ) { - fsp->pending_modtime = pmod; + fsp->pending_modtime = mod; fsp->pending_modtime_owner = False; } } diff --git a/source/smbd/msdfs.c b/source/smbd/msdfs.c index 2a19d6fb418..284061331bf 100644 --- a/source/smbd/msdfs.c +++ b/source/smbd/msdfs.c @@ -1,8 +1,9 @@ /* Unix SMB/Netbios implementation. Version 3.0 - MSDfs services for Samba + MSDFS services for Samba Copyright (C) Shirish Kalele 2000 + Copyright (C) Jeremy Allison 2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,108 +27,142 @@ extern uint32 global_client_caps; /********************************************************************** - Parse the pathname of the form \hostname\service\reqpath - into the dfs_path structure - **********************************************************************/ + Parse a DFS pathname of the form \hostname\service\reqpath + into the dfs_path structure. + If POSIX pathnames is true, the pathname may also be of the + form /hostname/service/reqpath. + We cope with either here. + + Unfortunately, due to broken clients who might set the + SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then + send a local path, we have to cope with that too.... -static BOOL parse_dfs_path(const char *pathname, struct dfs_path *pdp) + JRA. +**********************************************************************/ + +static NTSTATUS parse_dfs_path(const char *pathname, + BOOL allow_wcards, + struct dfs_path *pdp, + BOOL *ppath_contains_wcard) { pstring pathname_local; - char *p, *temp; + char *p,*temp; + NTSTATUS status = NT_STATUS_OK; + char sepchar; + + ZERO_STRUCTP(pdp); pstrcpy(pathname_local,pathname); p = temp = pathname_local; - ZERO_STRUCTP(pdp); + pdp->posix_path = (lp_posix_pathnames() && *pathname == '/'); - trim_char(temp,'\\','\\'); - DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp)); + sepchar = pdp->posix_path ? '/' : '\\'; - /* now tokenize */ - /* parse out hostname */ - p = strchr_m(temp,'\\'); - if(p == NULL) { - return False; - } - *p = '\0'; - pstrcpy(pdp->hostname,temp); - DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname)); + if (*pathname != sepchar) { + DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n", + pathname, sepchar )); + /* + * Possibly client sent a local path by mistake. + * Try and convert to a local path. + */ - /* parse out servicename */ - temp = p+1; - p = strchr_m(temp,'\\'); - if(p == NULL) { - pstrcpy(pdp->servicename,temp); - pdp->reqpath[0] = '\0'; - return True; + pdp->hostname[0] = '\0'; + pdp->servicename[0] = '\0'; + + /* We've got no info about separators. */ + pdp->posix_path = lp_posix_pathnames(); + p = temp; + DEBUG(10,("parse_dfs_path: trying to convert %s to a local path\n", + temp)); + goto local_path; } - *p = '\0'; - pstrcpy(pdp->servicename,temp); - DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename)); - /* rest is reqpath */ - check_path_syntax(pdp->reqpath, p+1); + trim_char(temp,sepchar,sepchar); - DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath)); - return True; -} + DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n", + temp, sepchar)); -/********************************************************************** - Parse the pathname of the form /hostname/service/reqpath - into the dfs_path structure - This code is dependent on the fact that check_path_syntax() will - convert '\\' characters to '/'. - When POSIX pathnames have been selected this doesn't happen, so we - must look for the unaltered separator of '\\' instead of the modified '/'. - JRA. - **********************************************************************/ + /* Now tokenize. */ + /* Parse out hostname. */ + p = strchr_m(temp,sepchar); + if(p == NULL) { + DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n", + temp)); + /* + * Possibly client sent a local path by mistake. + * Try and convert to a local path. + */ -static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path *pdp, BOOL allow_wcards) -{ - pstring pathname_local; - char *p,*temp; - const char sepchar = lp_posix_pathnames() ? '\\' : '/'; + pdp->hostname[0] = '\0'; + pdp->servicename[0] = '\0'; - pstrcpy(pathname_local,pathname); - p = temp = pathname_local; + p = temp; + DEBUG(10,("parse_dfs_path: trying to convert %s to a local path\n", + temp)); + goto local_path; + } + *p = '\0'; + fstrcpy(pdp->hostname,temp); + DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname)); - ZERO_STRUCTP(pdp); + /* If we got a hostname, is it ours (or an IP address) ? */ + if (!is_myname_or_ipaddr(pdp->hostname)) { + /* Repair path. */ + *p = sepchar; + DEBUG(10,("parse_dfs_path: hostname %s isn't ours. Try local path from path %s\n", + pdp->hostname, temp)); + /* + * Possibly client sent a local path by mistake. + * Try and convert to a local path. + */ - trim_char(temp,sepchar,sepchar); - DEBUG(10,("temp in parse_processed_dfs_path: .%s. after trimming \\'s\n",temp)); + pdp->hostname[0] = '\0'; + pdp->servicename[0] = '\0'; - /* now tokenize */ - /* parse out hostname */ - p = strchr_m(temp,sepchar); - if(p == NULL) { - return False; + p = temp; + DEBUG(10,("parse_dfs_path: trying to convert %s to a local path\n", + temp)); + goto local_path; } - *p = '\0'; - pstrcpy(pdp->hostname,temp); - DEBUG(10,("parse_processed_dfs_path: hostname: %s\n",pdp->hostname)); - /* parse out servicename */ + /* Parse out servicename. */ temp = p+1; p = strchr_m(temp,sepchar); if(p == NULL) { - pstrcpy(pdp->servicename,temp); + fstrcpy(pdp->servicename,temp); pdp->reqpath[0] = '\0'; - return True; + return NT_STATUS_OK; } *p = '\0'; - pstrcpy(pdp->servicename,temp); - DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename)); + fstrcpy(pdp->servicename,temp); + DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename)); + + p++; + + local_path: + + *ppath_contains_wcard = False; - /* rest is reqpath */ - if (allow_wcards) { - BOOL path_contains_wcard; - check_path_syntax_wcard(pdp->reqpath, p+1, &path_contains_wcard); + /* Rest is reqpath. */ + if (pdp->posix_path) { + status = check_path_syntax_posix(pdp->reqpath, p); } else { - check_path_syntax(pdp->reqpath, p+1); + if (allow_wcards) { + status = check_path_syntax_wcard(pdp->reqpath, p, ppath_contains_wcard); + } else { + status = check_path_syntax(pdp->reqpath, p); + } } - DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath)); - return True; + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("parse_dfs_path: '%s' failed with %s\n", + p, nt_errstr(status) )); + return status; + } + + DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath)); + return NT_STATUS_OK; } /******************************************************** @@ -135,7 +170,7 @@ static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path *pdp, BOOL Note this CHANGES CWD !!!! JRA. *********************************************************/ -static BOOL create_conn_struct(connection_struct *conn, int snum, char *path) +static BOOL create_conn_struct(connection_struct *conn, int snum, const char *path) { pstring connpath; @@ -145,19 +180,19 @@ static BOOL create_conn_struct(connection_struct *conn, int snum, char *path) pstring_sub(connpath , "%S", lp_servicename(snum)); /* needed for smbd_vfs_init() */ - - if ( (conn->mem_ctx=talloc_init("connection_struct")) == NULL ) { - DEBUG(0,("talloc_init(connection_struct) failed!\n")); - return False; - } - if (!(conn->params = TALLOC_P(conn->mem_ctx, struct share_params))) { + if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) { + DEBUG(0,("talloc_init(connection_struct) failed!\n")); + return False; + } + + if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx, struct share_params))) { DEBUG(0, ("TALLOC failed\n")); return False; } - + conn->params->service = snum; - + set_conn_connectpath(conn, connpath); if (!smbd_vfs_init(conn)) { @@ -184,11 +219,27 @@ static BOOL create_conn_struct(connection_struct *conn, int snum, char *path) /********************************************************************** Parse the contents of a symlink to verify if it is an msdfs referral - A valid referral is of the form: msdfs:server1\share1,server2\share2 - talloc CTX can be NULL here if preflist and refcount pointers are null. + A valid referral is of the form: + + msdfs:server1\share1,server2\share2 + msdfs:server1\share1\pathname,server2\share2\pathname + msdfs:server1/share1,server2/share2 + msdfs:server1/share1/pathname,server2/share2/pathname. + + Note that the alternate paths returned here must be of the canonicalized + form: + + \server\share or + \server\share\path\to\file, + + even in posix path mode. This is because we have no knowledge if the + server we're referring to understands posix paths. **********************************************************************/ -static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist, int *refcount) +static BOOL parse_msdfs_symlink(TALLOC_CTX *ctx, + char *target, + struct referral **preflist, + int *refcount) { pstring temp; char *prot; @@ -196,45 +247,28 @@ static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist int count = 0, i; struct referral *reflist; - pstrcpy(temp,buf); - + pstrcpy(temp,target); prot = strtok(temp,":"); - if (!strequal(prot, "msdfs")) { - return False; - } - - /* No referral list requested. Just yes/no. */ - if (!preflist) { - return True; - } - - if (!ctx) { - DEBUG(0,("parse_symlink: logic error. TALLOC_CTX should not be null.\n")); - return True; - } - /* parse out the alternate paths */ while((count<MAX_REFERRAL_COUNT) && ((alt_path[count] = strtok(NULL,",")) != NULL)) { count++; } - DEBUG(10,("parse_symlink: count=%d\n", count)); + DEBUG(10,("parse_msdfs_symlink: count=%d\n", count)); - reflist = *preflist = TALLOC_ARRAY(ctx, struct referral, count); + reflist = *preflist = TALLOC_ZERO_ARRAY(ctx, struct referral, count); if(reflist == NULL) { - DEBUG(0,("parse_symlink: talloc failed!\n")); + DEBUG(0,("parse_msdfs_symlink: talloc failed!\n")); return False; } for(i=0;i<count;i++) { char *p; - /* replace all /'s in the alternate path by a \ */ - for(p = alt_path[i]; *p && ((p = strchr_m(p,'/'))!=NULL); p++) { - *p = '\\'; - } + /* Canonicalize link target. Replace all /'s in the path by a \ */ + string_replace(alt_path[i], '/', '\\'); /* Remove leading '\\'s */ p = alt_path[i]; @@ -244,35 +278,29 @@ static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist pstrcpy(reflist[i].alternate_path, "\\"); pstrcat(reflist[i].alternate_path, p); + reflist[i].proximity = 0; reflist[i].ttl = REFERRAL_TTL; - DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path)); - } - - if(refcount) { - *refcount = count; + DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n", reflist[i].alternate_path)); + *refcount += 1; } return True; } /********************************************************************** - Returns true if the unix path is a valid msdfs symlink - talloc CTX can be NULL here if reflistp and refcnt pointers are null. - **********************************************************************/ + Returns true if the unix path is a valid msdfs symlink and also + returns the target string from inside the link. +**********************************************************************/ -BOOL is_msdfs_link(TALLOC_CTX *ctx, connection_struct *conn, const char *path, - struct referral **reflistp, int *refcnt, - SMB_STRUCT_STAT *sbufp) +BOOL is_msdfs_link(connection_struct *conn, + const char *path, + pstring link_target, + SMB_STRUCT_STAT *sbufp) { SMB_STRUCT_STAT st; - pstring referral; int referral_len = 0; - if (!path || !conn) { - return False; - } - if (sbufp == NULL) { sbufp = &st; } @@ -282,76 +310,59 @@ BOOL is_msdfs_link(TALLOC_CTX *ctx, connection_struct *conn, const char *path, return False; } - if (S_ISLNK(sbufp->st_mode)) { - /* open the link and read it */ - referral_len = SMB_VFS_READLINK(conn, path, referral, sizeof(pstring)-1); - if (referral_len == -1) { - DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno))); - return False; - } + if (!S_ISLNK(sbufp->st_mode)) { + DEBUG(5,("is_msdfs_link: %s is not a link.\n",path)); + return False; + } - referral[referral_len] = '\0'; - DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral)); - if (parse_symlink(ctx, referral, reflistp, refcnt)) { - return True; - } + /* open the link and read it */ + referral_len = SMB_VFS_READLINK(conn, path, link_target, sizeof(pstring)-1); + if (referral_len == -1) { + DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", + path, strerror(errno))); + return False; + } + link_target[referral_len] = '\0'; + + DEBUG(5,("is_msdfs_link: %s -> %s\n",path, link_target)); + + if (!strnequal(link_target, "msdfs:", 6)) { + return False; } - return False; + return True; } /***************************************************************** Used by other functions to decide if a dfs path is remote, -and to get the list of referred locations for that remote path. + and to get the list of referred locations for that remote path. -findfirst_flag: For findfirsts, dfs links themselves are not -redirected, but paths beyond the links are. For normal smb calls, -even dfs links need to be redirected. + search_flag: For findfirsts, dfs links themselves are not + redirected, but paths beyond the links are. For normal smb calls, + even dfs links need to be redirected. -self_referralp: clients expect a dfs referral for the same share when -they request referrals for dfs roots on a server. + consumedcntp: how much of the dfs path is being redirected. the client + should try the remaining path on the redirected server. -consumedcntp: how much of the dfs path is being redirected. the client -should try the remaining path on the redirected server. - -TALLOC_CTX can be NULL here if struct referral **reflistpp, int *refcntp -are also NULL. + If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs + link redirect are in targetpath. *****************************************************************/ -static BOOL resolve_dfs_path(TALLOC_CTX *ctx, - const char *dfspath, - struct dfs_path *dp, - connection_struct *conn, - BOOL search_flag, - struct referral **reflistpp, - int *refcntp, - BOOL *self_referralp, - int *consumedcntp) +static NTSTATUS dfs_path_lookup(connection_struct *conn, + const char *dfspath, /* Incoming complete dfs path */ + const struct dfs_path *pdp, /* Parsed out server+share+extrapath. */ + BOOL search_flag, /* Called from a findfirst ? */ + int *consumedcntp, + pstring targetpath) { - pstring localpath; - int consumed_level = 1; - char *p; + char *p = NULL; + char *q = NULL; SMB_STRUCT_STAT sbuf; NTSTATUS status; - pstring reqpath; - - if (!dp || !conn) { - DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n")); - return False; - } - - if (!ctx && (reflistpp || refcntp)) { - DEBUG(0,("resolve_dfs_path: logic error. TALLOC_CTX must not be NULL.\n")); - } - - if (dp->reqpath[0] == '\0') { - if (self_referralp) { - DEBUG(6,("resolve_dfs_path: self-referral. returning False\n")); - *self_referralp = True; - } - return False; - } + pstring localpath; + pstring canon_dfspath; /* Canonicalized dfs path. (only '/' components). */ - DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath)); + DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n", + conn->connectpath, pdp->reqpath)); /* * Note the unix path conversion here we're doing we can @@ -365,144 +376,189 @@ static BOOL resolve_dfs_path(TALLOC_CTX *ctx, * think this is needed. JRA. */ - pstrcpy(localpath, dp->reqpath); - - status = unix_convert(conn, localpath, False, NULL, &sbuf); + pstrcpy(localpath, pdp->reqpath); + status = unix_convert(conn, localpath, search_flag, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { - return False; + return status; } - /* check if need to redirect */ - if (is_msdfs_link(ctx, conn, localpath, reflistpp, refcntp, NULL)) { - if ( search_flag ) { - DEBUG(6,("resolve_dfs_path (FindFirst) No redirection " + /* Optimization - check if we can redirect the whole path. */ + + if (is_msdfs_link(conn, localpath, targetpath, NULL)) { + if (search_flag) { + DEBUG(6,("dfs_path_lookup (FindFirst) No redirection " "for dfs link %s.\n", dfspath)); - return False; + return NT_STATUS_OK; } - DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n", dfspath)); + DEBUG(6,("dfs_path_lookup: %s resolves to a " + "valid dfs link %s.\n", dfspath, targetpath)); + if (consumedcntp) { *consumedcntp = strlen(dfspath); } - return True; + return NT_STATUS_PATH_NOT_COVERED; + } + + /* Prepare to test only for '/' components in the given path, + * so if a Windows path replace all '\\' characters with '/'. + * For a POSIX DFS path we know all separators are already '/'. */ + + pstrcpy(canon_dfspath, dfspath); + if (!pdp->posix_path) { + string_replace(canon_dfspath, '\\', '/'); + } + + /* + * Redirect if any component in the path is a link. + * We do this by walking backwards through the + * local path, chopping off the last component + * in both the local path and the canonicalized + * DFS path. If we hit a DFS link then we're done. + */ + + p = strrchr_m(localpath, '/'); + if (consumedcntp) { + q = strrchr_m(canon_dfspath, '/'); } - /* redirect if any component in the path is a link */ - pstrcpy(reqpath, localpath); - p = strrchr_m(reqpath, '/'); while (p) { *p = '\0'; - pstrcpy(localpath, reqpath); - if (is_msdfs_link(ctx, conn, localpath, reflistpp, refcntp, NULL)) { - DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath)); - - /* To find the path consumed, we truncate the original - DFS pathname passed to use to remove the last - component. The length of the resulting string is - the path consumed - */ - + if (q) { + *q = '\0'; + } + + if (is_msdfs_link(conn, localpath, targetpath, NULL)) { + DEBUG(4, ("dfs_path_lookup: Redirecting %s because " + "parent %s is dfs link\n", dfspath, localpath)); + if (consumedcntp) { - char *q; - pstring buf; - pstrcpy(buf, dfspath); - trim_char(buf, '\0', '\\'); - for (; consumed_level; consumed_level--) { - q = strrchr_m(buf, '\\'); - if (q) { - *q = 0; - } - } - *consumedcntp = strlen(buf); - DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp)); + *consumedcntp = strlen(canon_dfspath); + DEBUG(10, ("dfs_path_lookup: Path consumed: %s " + "(%d)\n", canon_dfspath, *consumedcntp)); } - - return True; + + return NT_STATUS_PATH_NOT_COVERED; + } + + /* Step back on the filesystem. */ + p = strrchr_m(localpath, '/'); + + if (consumedcntp) { + /* And in the canonicalized dfs path. */ + q = strrchr_m(canon_dfspath, '/'); } - p = strrchr_m(reqpath, '/'); - consumed_level++; } - return False; + return NT_STATUS_OK; } /***************************************************************** - Decides if a dfs pathname should be redirected or not. - If not, the pathname is converted to a tcon-relative local unix path - - search_wcard_flag: this flag performs 2 functions bother related - to searches. See resolve_dfs_path() and parse_processed_dfs_path() - for details. + Decides if a dfs pathname should be redirected or not. + If not, the pathname is converted to a tcon-relative local unix path + + search_wcard_flag: this flag performs 2 functions bother related + to searches. See resolve_dfs_path() and parse_dfs_path_XX() + for details. + + This function can return NT_STATUS_OK, meaning use the returned path as-is + (mapped into a local path). + or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or + any other NT_STATUS error which is a genuine error to be + returned to the client. *****************************************************************/ -BOOL dfs_redirect( pstring pathname, connection_struct *conn, BOOL search_wcard_flag ) +static NTSTATUS dfs_redirect( connection_struct *conn, + pstring dfs_path, + BOOL search_wcard_flag, + BOOL *ppath_contains_wcard) { + NTSTATUS status; struct dfs_path dp; + pstring targetpath; - if (!conn || !pathname) { - return False; + status = parse_dfs_path(dfs_path, search_wcard_flag, &dp, ppath_contains_wcard); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (dp.reqpath[0] == '\0') { + pstrcpy(dfs_path, dp.reqpath); + DEBUG(5,("dfs_redirect: self-referral.\n")); + return NT_STATUS_OK; } - parse_processed_dfs_path(pathname, &dp, search_wcard_flag); + /* If dfs pathname for a non-dfs share, convert to tcon-relative + path and return OK */ - /* if dfs pathname for a non-dfs share, convert to tcon-relative - path and return false */ if (!lp_msdfs_root(SNUM(conn))) { - pstrcpy(pathname, dp.reqpath); - return False; + pstrcpy(dfs_path, dp.reqpath); + return NT_STATUS_OK; } - - if ( !( strequal(dp.servicename, lp_servicename(SNUM(conn))) - || ( strequal(dp.servicename, HOMES_NAME) - && strequal(lp_servicename(SNUM(conn)), get_current_username()) )) ) - { - return False; + + /* If it looked like a local path (zero hostname/servicename) + * just treat as a tcon-relative path. */ + + if (dp.hostname[0] == '\0' && dp.servicename[0] == '\0') { + pstrcpy(dfs_path, dp.reqpath); + return NT_STATUS_OK; } - if (resolve_dfs_path(NULL, pathname, &dp, conn, search_wcard_flag, - NULL, NULL, NULL, NULL)) { - DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname)); - return True; - } else { - DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname)); + if (!( strequal(dp.servicename, lp_servicename(SNUM(conn))) + || (strequal(dp.servicename, HOMES_NAME) + && strequal(lp_servicename(SNUM(conn)), get_current_username()) )) ) { - /* Form non-dfs tcon-relative path */ - pstrcpy(pathname, dp.reqpath); + /* The given sharename doesn't match this connection. */ - DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n", pathname)); - return False; + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + + status = dfs_path_lookup(conn, dfs_path, &dp, + search_wcard_flag, NULL, targetpath); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) { + DEBUG(3,("dfs_redirect: Redirecting %s\n", dfs_path)); + } else { + DEBUG(10,("dfs_redirect: dfs_path_lookup failed for %s with %s\n", + dfs_path, nt_errstr(status) )); + } + return status; } - /* never reached */ + DEBUG(3,("dfs_redirect: Not redirecting %s.\n", dfs_path)); + + /* Form non-dfs tcon-relative path */ + pstrcpy(dfs_path, dp.reqpath); + + DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n", dfs_path)); + return NT_STATUS_OK; } /********************************************************************** Return a self referral. **********************************************************************/ -static BOOL self_ref(TALLOC_CTX *ctx, const char *pathname, struct junction_map *jucn, - int *consumedcntp, BOOL *self_referralp) +static BOOL self_ref(TALLOC_CTX *ctx, + const char *dfs_path, + struct junction_map *jucn, + int *consumedcntp, + BOOL *self_referralp) { struct referral *ref; - if (self_referralp != NULL) { - *self_referralp = True; - } + *self_referralp = True; jucn->referral_count = 1; - if((ref = TALLOC_P(ctx, struct referral)) == NULL) { - DEBUG(0,("self_ref: malloc failed for referral\n")); + if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) { + DEBUG(0,("self_ref: talloc failed for referral\n")); return False; } - pstrcpy(ref->alternate_path,pathname); + pstrcpy(ref->alternate_path,dfs_path); ref->proximity = 0; ref->ttl = REFERRAL_TTL; jucn->referral_list = ref; - if (consumedcntp) { - *consumedcntp = strlen(pathname); - } - + *consumedcntp = strlen(dfs_path); return True; } @@ -511,40 +567,39 @@ static BOOL self_ref(TALLOC_CTX *ctx, const char *pathname, struct junction_map junction_map structure. **********************************************************************/ -BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_map *jucn, - int *consumedcntp, BOOL *self_referralp) +BOOL get_referred_path(TALLOC_CTX *ctx, + const char *dfs_path, + struct junction_map *jucn, + int *consumedcntp, + BOOL *self_referralp) { - struct dfs_path dp; - struct connection_struct conns; struct connection_struct *conn = &conns; + struct dfs_path dp; pstring conn_path; + pstring targetpath; int snum; + NTSTATUS status; BOOL ret = False; - BOOL self_referral = False; - - if (!pathname || !jucn) { - return False; - } + BOOL dummy; ZERO_STRUCT(conns); - if (self_referralp) { - *self_referralp = False; - } else { - self_referralp = &self_referral; - } + *self_referralp = False; - parse_dfs_path(pathname, &dp); + status = parse_dfs_path(dfs_path, False, &dp, &dummy); + if (!NT_STATUS_IS_OK(status)) { + return False; + } /* Verify hostname in path */ if (!is_myname_or_ipaddr(dp.hostname)) { DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n", - dp.hostname, pathname)); + dp.hostname, dfs_path)); return False; } - pstrcpy(jucn->service_name, dp.servicename); + fstrcpy(jucn->service_name, dp.servicename); pstrcpy(jucn->volume_name, dp.reqpath); /* Verify the share is a dfs root */ @@ -556,8 +611,8 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma } if (!lp_msdfs_root(snum)) { - DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n", - dp.servicename, pathname)); + DEBUG(3,("get_referred_path: |%s| in dfs path %s is not a dfs root.\n", + dp.servicename, dfs_path)); goto out; } @@ -569,15 +624,23 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma */ if (dp.reqpath[0] == '\0') { - - struct referral* ref; + struct referral *ref; if (*lp_msdfs_proxy(snum) == '\0') { - return self_ref(ctx, pathname, jucn, consumedcntp, self_referralp); + return self_ref(ctx, + dfs_path, + jucn, + consumedcntp, + self_referralp); } + /* + * It's an msdfs proxy share. Redirect to + * the configured target share. + */ + jucn->referral_count = 1; - if ((ref = TALLOC_P(ctx, struct referral)) == NULL) { + if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) { DEBUG(0, ("malloc failed for referral\n")); goto out; } @@ -589,9 +652,7 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma ref->proximity = 0; ref->ttl = REFERRAL_TTL; jucn->referral_list = ref; - if (consumedcntp) { - *consumedcntp = strlen(pathname); - } + *consumedcntp = strlen(dfs_path); ret = True; goto out; } @@ -601,23 +662,27 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma return False; } - /* If not remote & not a self referral, return False */ - if (!resolve_dfs_path(ctx, pathname, &dp, conn, False, - &jucn->referral_list, &jucn->referral_count, - self_referralp, consumedcntp)) { - if (!*self_referralp) { - DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname)); - goto out; - } + /* If this is a DFS path dfs_lookup should return + * NT_STATUS_PATH_NOT_COVERED. */ + + status = dfs_path_lookup(conn, dfs_path, &dp, + False, consumedcntp, targetpath); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) { + DEBUG(3,("get_referred_path: No valid referrals for path %s\n", + dfs_path)); + goto out; } - - /* if self_referral, fill up the junction map */ - if (*self_referralp) { - if (self_ref(ctx, pathname, jucn, consumedcntp, self_referralp) == False) { - goto out; - } + + /* We know this is a valid dfs link. Parse the targetpath. */ + if (!parse_msdfs_symlink(ctx, targetpath, + &jucn->referral_list, + &jucn->referral_count)) { + DEBUG(3,("get_referred_path: failed to parse symlink " + "target %s\n", targetpath )); + goto out; } - + ret = True; out: @@ -626,10 +691,11 @@ out: return ret; } -static int setup_ver2_dfs_referral(char *pathname, char **ppdata, - struct junction_map *junction, - int consumedcnt, - BOOL self_referral) +static int setup_ver2_dfs_referral(const char *pathname, + char **ppdata, + struct junction_map *junction, + int consumedcnt, + BOOL self_referral) { char* pdata = *ppdata; @@ -641,7 +707,7 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata, int reply_size = 0; int i=0; - DEBUG(10,("setting up version2 referral\nRequested path:\n")); + DEBUG(10,("Setting up version2 referral\nRequested path:\n")); requestedpathlen = rpcstr_push(uni_requestedpath, pathname, sizeof(pstring), STR_TERMINATE); @@ -675,7 +741,7 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata, pdata = (char *)SMB_REALLOC(pdata,reply_size); if(pdata == NULL) { - DEBUG(0,("malloc failed for Realloc!\n")); + DEBUG(0,("Realloc failed!\n")); return -1; } *ppdata = pdata; @@ -726,10 +792,11 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata, return reply_size; } -static int setup_ver3_dfs_referral(char *pathname, char **ppdata, - struct junction_map *junction, - int consumedcnt, - BOOL self_referral) +static int setup_ver3_dfs_referral(const char *pathname, + char **ppdata, + struct junction_map *junction, + int consumedcnt, + BOOL self_referral) { char* pdata = *ppdata; @@ -810,17 +877,23 @@ static int setup_ver3_dfs_referral(char *pathname, char **ppdata, } /****************************************************************** - Set up the Dfs referral for the dfs pathname + Set up the DFS referral for the dfs pathname. This call returns + the amount of the path covered by this server, and where the + client should be redirected to. This is the meat of the + TRANS2_GET_DFS_REFERRAL call. ******************************************************************/ -int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_referral_level, char **ppdata) +int setup_dfs_referral(connection_struct *orig_conn, + const char *dfs_path, + int max_referral_level, + char **ppdata) { struct junction_map junction; - int consumedcnt; + int consumedcnt = 0; BOOL self_referral = False; - pstring buf; int reply_size = 0; - char *pathnamep = pathname; + char *pathnamep = NULL; + pstring local_dfs_path; TALLOC_CTX *ctx; if (!(ctx=talloc_init("setup_dfs_referral"))) { @@ -830,21 +903,24 @@ int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_ref ZERO_STRUCT(junction); /* get the junction entry */ - if (!pathnamep) { + if (!dfs_path) { talloc_destroy(ctx); return -1; } - /* Trim pathname sent by client so it begins with only one backslash. - Two backslashes confuse some dfs clients + /* + * Trim pathname sent by client so it begins with only one backslash. + * Two backslashes confuse some dfs clients */ - while (pathnamep[0] == '\\' && pathnamep[1] == '\\') { + + pstrcpy(local_dfs_path, dfs_path); + pathnamep = local_dfs_path; + while (IS_DIRECTORY_SEP(pathnamep[0]) && IS_DIRECTORY_SEP(pathnamep[1])) { pathnamep++; } - pstrcpy(buf, pathnamep); /* The following call can change cwd. */ - if (!get_referred_path(ctx, buf, &junction, &consumedcnt, &self_referral)) { + if (!get_referred_path(ctx, pathnamep, &junction, &consumedcnt, &self_referral)) { vfs_ChDir(orig_conn,orig_conn->connectpath); talloc_destroy(ctx); return -1; @@ -902,31 +978,40 @@ int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_ref **********************************************************************/ /********************************************************************* - Creates a junction structure from a Dfs pathname + Creates a junction structure from a DFS pathname **********************************************************************/ -BOOL create_junction(const char *pathname, struct junction_map *jucn) +BOOL create_junction(const char *dfs_path, struct junction_map *jucn) { - struct dfs_path dp; + int snum; + BOOL dummy; + struct dfs_path dp; - parse_dfs_path(pathname,&dp); + NTSTATUS status = parse_dfs_path(dfs_path, False, &dp, &dummy); + + if (!NT_STATUS_IS_OK(status)) { + return False; + } - /* check if path is dfs : validate first token */ + /* check if path is dfs : validate first token */ if (!is_myname_or_ipaddr(dp.hostname)) { DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n", - dp.hostname, pathname)); + dp.hostname, dfs_path)); return False; } /* Check for a non-DFS share */ - if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) { - DEBUG(4,("create_junction: %s is not an msdfs root.\n", dp.servicename)); + snum = lp_servicenumber(dp.servicename); + + if(snum < 0 || !lp_msdfs_root(snum)) { + DEBUG(4,("create_junction: %s is not an msdfs root.\n", + dp.servicename)); return False; } - pstrcpy(jucn->service_name,dp.servicename); + fstrcpy(jucn->service_name,dp.servicename); pstrcpy(jucn->volume_name,dp.reqpath); - pstrcpy(jucn->comment, lp_comment(lp_servicenumber(dp.servicename))); + pstrcpy(jucn->comment, lp_comment(snum)); return True; } @@ -934,16 +1019,14 @@ BOOL create_junction(const char *pathname, struct junction_map *jucn) Forms a valid Unix pathname from the junction **********************************************************************/ -static BOOL junction_to_local_path(struct junction_map *jucn, char *path, - int max_pathlen, connection_struct *conn) +static BOOL junction_to_local_path(struct junction_map *jucn, + char *path, + int max_pathlen, + connection_struct *conn_out) { int snum; pstring conn_path; - if(!path || !jucn) { - return False; - } - snum = lp_servicenumber(jucn->service_name); if(snum < 0) { return False; @@ -954,7 +1037,7 @@ static BOOL junction_to_local_path(struct junction_map *jucn, char *path, safe_strcat(path, jucn->volume_name, max_pathlen-1); pstrcpy(conn_path, lp_pathname(snum)); - if (!create_conn_struct(conn, snum, conn_path)) { + if (!create_conn_struct(conn_out, snum, conn_path)) { return False; } @@ -977,11 +1060,12 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists) return False; } - /* form the msdfs_link contents */ + /* Form the msdfs_link contents */ pstrcpy(msdfs_link, "msdfs:"); for(i=0; i<jucn->referral_count; i++) { char* refpath = jucn->referral_list[i].alternate_path; + /* Alternate paths always use Windows separators. */ trim_char(refpath, '\\', '\\'); if(*refpath == '\0') { if (i == 0) { @@ -999,7 +1083,8 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists) } } - DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link)); + DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", + path, msdfs_link)); if(exists) { if(SMB_VFS_UNLINK(conn,path)!=0) { @@ -1015,7 +1100,7 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists) ret = True; - + out: conn_free_internal(conn); @@ -1042,13 +1127,16 @@ BOOL remove_msdfs_link(struct junction_map *jucn) return ret; } -static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn, int jn_remain) +static int form_junctions(TALLOC_CTX *ctx, + int snum, + struct junction_map *jucn, + int jn_remain) { int cnt = 0; SMB_STRUCT_DIR *dirp; - char* dname; + char *dname; pstring connect_path; - char* service_name = lp_servicename(snum); + char *service_name = lp_servicename(snum); connection_struct conn; struct referral *ref = NULL; @@ -1076,13 +1164,13 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn, DO NOT REMOVE THIS: NT clients will not work with us if this is not present */ - pstrcpy(jucn[cnt].service_name, service_name); + fstrcpy(jucn[cnt].service_name, service_name); jucn[cnt].volume_name[0] = '\0'; jucn[cnt].referral_count = 1; - ref = jucn[cnt].referral_list = TALLOC_P(ctx, struct referral); + ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral); if (jucn[cnt].referral_list == NULL) { - DEBUG(0, ("Malloc failed!\n")); + DEBUG(0, ("talloc failed!\n")); goto out; } @@ -1093,9 +1181,10 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn, cnt++; goto out; } - - slprintf(ref->alternate_path, sizeof(pstring)-1, - "\\\\%s\\%s", get_local_machine_name(), service_name); + + pstr_sprintf(ref->alternate_path, "\\\\%s\\%s", + get_local_machine_name(), + service_name); cnt++; /* Now enumerate all dfs links */ @@ -1105,16 +1194,22 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn, } while ((dname = vfs_readdirname(&conn, dirp)) != NULL) { + pstring link_target; if (cnt >= jn_remain) { SMB_VFS_CLOSEDIR(&conn,dirp); DEBUG(2, ("ran out of MSDFS junction slots")); goto out; } - if (is_msdfs_link(ctx, &conn, dname, &jucn[cnt].referral_list, - &jucn[cnt].referral_count, NULL)) { - pstrcpy(jucn[cnt].service_name, service_name); - pstrcpy(jucn[cnt].volume_name, dname); - cnt++; + if (is_msdfs_link(&conn, dname, link_target, NULL)) { + if (parse_msdfs_symlink(ctx, + link_target, + &jucn[cnt].referral_list, + &jucn[cnt].referral_count)) { + + fstrcpy(jucn[cnt].service_name, service_name); + pstrcpy(jucn[cnt].volume_name, dname); + cnt++; + } } } @@ -1148,3 +1243,33 @@ int enum_msdfs_links(TALLOC_CTX *ctx, struct junction_map *jucn, int jn_max) } return jn_count; } + +/****************************************************************************** + Core function to resolve a dfs pathname. +******************************************************************************/ + +NTSTATUS resolve_dfspath(connection_struct *conn, BOOL dfs_pathnames, pstring name) +{ + NTSTATUS status = NT_STATUS_OK; + BOOL dummy; + if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn))) { + status = dfs_redirect(conn, name, False, &dummy); + } + return status; +} + +/****************************************************************************** + Core function to resolve a dfs pathname possibly containing a wildcard. + This function is identical to the above except for the BOOL param to + dfs_redirect but I need this to be separate so it's really clear when + we're allowing wildcards and when we're not. JRA. +******************************************************************************/ + +NTSTATUS resolve_dfspath_wcard(connection_struct *conn, BOOL dfs_pathnames, pstring name, BOOL *ppath_contains_wcard) +{ + NTSTATUS status = NT_STATUS_OK; + if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn))) { + status = dfs_redirect(conn, name, True, ppath_contains_wcard); + } + return status; +} diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c index fb5610b20bb..bc7c75aab4c 100644 --- a/source/smbd/negprot.c +++ b/source/smbd/negprot.c @@ -259,7 +259,9 @@ static int reply_nt1(char *inbuf, char *outbuf) if ( (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY) && ((SVAL(inbuf, smb_flg2) & FLAGS2_UNKNOWN_BIT4) == 0) ) { - set_remote_arch( RA_VISTA ); + if (get_remote_arch() != RA_SAMBA) { + set_remote_arch( RA_VISTA ); + } } /* do spnego in user level security if the client diff --git a/source/smbd/notify_inotify.c b/source/smbd/notify_inotify.c index 5fb414de4cc..ff17d455f39 100644 --- a/source/smbd/notify_inotify.c +++ b/source/smbd/notify_inotify.c @@ -26,6 +26,10 @@ #ifdef HAVE_INOTIFY +#ifdef HAVE_ASM_TYPES_H +#include <asm/types.h> +#endif + #include <linux/inotify.h> #include <asm/unistd.h> diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 19710d1dcdd..2a49e1f4a64 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -353,7 +353,7 @@ static int nt_open_pipe(char *fname, connection_struct *conn, return(ERROR_DOS(ERRSRV,ERRnofids)); } - /* TODO: Add pipe to db */ + /* Add pipe to db */ if ( !store_pipe_opendb( p ) ) { DEBUG(3,("nt_open_pipe: failed to store %s pipe open.\n", fname)); @@ -469,7 +469,7 @@ int reply_ntcreate_and_X(connection_struct *conn, SMB_OFF_T file_len = 0; SMB_STRUCT_STAT sbuf; int info = 0; - files_struct *fsp=NULL; + files_struct *fsp = NULL; char *p = NULL; struct timespec c_timespec; struct timespec a_timespec; @@ -491,7 +491,9 @@ int reply_ntcreate_and_X(connection_struct *conn, (unsigned int)create_options, (unsigned int)root_dir_fid )); - /* If it's an IPC, use the pipe handler. */ + /* + * If it's an IPC, use the pipe handler. + */ if (IS_IPC(conn)) { if (lp_nt_pipe_support()) { @@ -502,7 +504,7 @@ int reply_ntcreate_and_X(connection_struct *conn, return(ERROR_DOS(ERRDOS,ERRnoaccess)); } } - + if (create_options & FILE_OPEN_BY_FILE_ID) { END_PROFILE(SMBntcreateX); return ERROR_NT(NT_STATUS_NOT_SUPPORTED); @@ -522,7 +524,7 @@ int reply_ntcreate_and_X(connection_struct *conn, if(!dir_fsp) { END_PROFILE(SMBntcreateX); - return(ERROR_DOS(ERRDOS,ERRbadfid)); + return ERROR_DOS(ERRDOS,ERRbadfid); } if(!dir_fsp->is_directory) { @@ -533,7 +535,7 @@ int reply_ntcreate_and_X(connection_struct *conn, return ERROR_NT(status); } - /* + /* * Check to see if this is a mac fork of some kind. */ @@ -564,7 +566,7 @@ int reply_ntcreate_and_X(connection_struct *conn, * Ensure it ends in a '\'. */ - if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') { + if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) { pstrcat(fname, "/"); dir_name_len++; } @@ -582,7 +584,7 @@ int reply_ntcreate_and_X(connection_struct *conn, return ERROR_NT(status); } - /* + /* * Check to see if this is a mac fork of some kind. */ @@ -613,7 +615,14 @@ int reply_ntcreate_and_X(connection_struct *conn, * Now contruct the smb_open_mode value from the filename, * desired access and the share access. */ - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBntcreateX); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; if (oplock_request) { @@ -664,19 +673,19 @@ int reply_ntcreate_and_X(connection_struct *conn, } } - /* + /* * If it's a request for a directory open, deal with it separately. */ if(create_options & FILE_DIRECTORY_FILE) { - oplock_request = 0; - + /* Can't open a temp directory. IFS kit test. */ if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { END_PROFILE(SMBntcreateX); return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } + oplock_request = 0; status = open_directory(conn, fname, &sbuf, access_mask, share_access, @@ -695,7 +704,9 @@ int reply_ntcreate_and_X(connection_struct *conn, END_PROFILE(SMBntcreateX); return ERROR_NT(status); } + } else { + /* * Ordinary file case. */ @@ -721,6 +732,7 @@ int reply_ntcreate_and_X(connection_struct *conn, new_file_attributes, oplock_request, &info, &fsp); + if (!NT_STATUS_IS_OK(status)) { /* We cheat here. There are two cases we * care about. One is a directory rename, @@ -773,7 +785,6 @@ int reply_ntcreate_and_X(connection_struct *conn, return ERROR_NT(status); } } else { - restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); if (open_was_deferred(SVAL(inbuf,smb_mid))) { @@ -786,7 +797,7 @@ int reply_ntcreate_and_X(connection_struct *conn, } restore_case_semantics(conn, file_attributes); - + file_len = sbuf.st_size; fattr = dos_mode(conn,fname,&sbuf); if(fattr == 0) { @@ -827,11 +838,11 @@ int reply_ntcreate_and_X(connection_struct *conn, * and we granted one (by whatever means) - set the * correct bit for extended oplock reply. */ - + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { extended_oplock_granted = True; } - + if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { extended_oplock_granted = True; } @@ -871,8 +882,8 @@ int reply_ntcreate_and_X(connection_struct *conn, SIVAL(p,0,info); } p += 4; - - /* Create time. */ + + /* Create time. */ c_timespec = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn))); a_timespec = get_atimespec(&sbuf); m_timespec = get_mtimespec(&sbuf); @@ -883,7 +894,7 @@ int reply_ntcreate_and_X(connection_struct *conn, dos_filetime_timespec(&m_timespec); } - put_long_date_timespec(p, c_timespec); + put_long_date_timespec(p, c_timespec); /* create time. */ p += 8; put_long_date_timespec(p, a_timespec); /* access time */ p += 8; @@ -1252,15 +1263,27 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o } oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; - oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; + if (oplock_request) { + oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; + } /* + * Ordinary file or directory. + */ + + /* * Check if POSIX semantics are wanted. */ - + new_file_attributes = set_posix_case_semantics(conn, file_attributes); - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, fname, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -1273,7 +1296,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o restore_case_semantics(conn, file_attributes); return ERROR_NT(status); } - + /* This is the correct thing to do (check every time) but can_delete is expensive (it may have to read the parent directory permissions). So for now we're not doing it unless we have a strong hint the client @@ -1317,14 +1340,13 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } - oplock_request = 0; - /* * We will get a create directory here if the Win32 * app specified a security descriptor in the * CreateDirectory() call. */ + oplock_request = 0; status = open_directory(conn, fname, &sbuf, access_mask, share_access, @@ -1464,11 +1486,11 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o * and we granted one (by whatever means) - set the * correct bit for extended oplock reply. */ - + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { extended_oplock_granted = True; } - + if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { extended_oplock_granted = True; } @@ -1592,15 +1614,15 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new return status; } - /* Source must already exist. */ - if (!VALID_STAT(sbuf1)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } status = check_name(conn, oldname); if (!NT_STATUS_IS_OK(status)) { return status; } + /* Source must already exist. */ + if (!VALID_STAT(sbuf1)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } /* Ensure attributes match. */ fattr = dos_mode(conn,oldname,&sbuf1); if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) { @@ -1612,16 +1634,16 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new return status; } - /* Disallow if newname already exists. */ - if (VALID_STAT(sbuf2)) { - return NT_STATUS_OBJECT_NAME_COLLISION; - } - status = check_name(conn, newname); if (!NT_STATUS_IS_OK(status)) { return status; } + /* Disallow if newname already exists. */ + if (VALID_STAT(sbuf2)) { + return NT_STATUS_OBJECT_NAME_COLLISION; + } + /* No links from a directory. */ if (S_ISDIR(sbuf1.st_mode)) { return NT_STATUS_FILE_IS_A_DIRECTORY; @@ -1675,7 +1697,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - fsp_set_pending_modtime(fsp2, sbuf1.st_mtime); + fsp_set_pending_modtime(fsp2, get_mtimespec(&sbuf1)); status = close_file(fsp2,NORMAL_CLOSE); @@ -1708,15 +1730,15 @@ int reply_ntrename(connection_struct *conn, pstring newname; char *p; NTSTATUS status; - BOOL path1_contains_wcard = False; - BOOL path2_contains_wcard = False; + BOOL src_has_wcard = False; + BOOL dest_has_wcard = False; uint32 attrs = SVAL(inbuf,smb_vwv0); uint16 rename_type = SVAL(inbuf,smb_vwv1); START_PROFILE(SMBntrename); p = smb_buf(inbuf) + 1; - p += srvstr_get_path_wcard(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, &path1_contains_wcard); + p += srvstr_get_path_wcard(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, &src_has_wcard); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBntrename); return ERROR_NT(status); @@ -1734,23 +1756,38 @@ int reply_ntrename(connection_struct *conn, } p++; - p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path2_contains_wcard); + p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBntrename); return ERROR_NT(status); } - RESOLVE_DFSPATH(oldname, conn, inbuf, outbuf); - RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); - + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBntrename); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } + + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBntrename); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } + DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname)); switch(rename_type) { case RENAME_FLAG_RENAME: - status = rename_internals(conn, oldname, newname, attrs, False, path1_contains_wcard); + status = rename_internals(conn, oldname, newname, attrs, False, src_has_wcard, dest_has_wcard); break; case RENAME_FLAG_HARD_LINK: - if (path1_contains_wcard || path2_contains_wcard) { + if (src_has_wcard || dest_has_wcard) { /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { @@ -1758,7 +1795,7 @@ int reply_ntrename(connection_struct *conn, } break; case RENAME_FLAG_COPY: - if (path1_contains_wcard || path2_contains_wcard) { + if (src_has_wcard || dest_has_wcard) { /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { @@ -1899,7 +1936,7 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o pstring new_name; files_struct *fsp = NULL; BOOL replace_if_exists = False; - BOOL path_contains_wcard = False; + BOOL dest_has_wcard = False; NTSTATUS status; if(parameter_count < 5) { @@ -1909,13 +1946,14 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o fsp = file_fsp(params, 0); replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; CHECK_FSP(fsp, conn); - srvstr_get_path_wcard(inbuf, new_name, params+4, sizeof(new_name), parameter_count - 4, STR_TERMINATE, &status, &path_contains_wcard); + srvstr_get_path_wcard(inbuf, new_name, params+4, sizeof(new_name), parameter_count - 4, + STR_TERMINATE, &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } status = rename_internals(conn, fsp->fsp_name, - new_name, 0, replace_if_exists, path_contains_wcard); + new_name, 0, replace_if_exists, False, dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(SVAL(inbuf,smb_mid))) { diff --git a/source/smbd/open.c b/source/smbd/open.c index 13ec9f952fe..c7a7086894e 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -1903,7 +1903,6 @@ static NTSTATUS mkdir_internal(connection_struct *conn, uint32 file_attributes, SMB_STRUCT_STAT *psbuf) { - int ret= -1; mode_t mode; char *parent_dir; const char *dirname; @@ -1931,7 +1930,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn, mode = unix_mode(conn, aDIR, name, parent_dir); } - if ((ret=SMB_VFS_MKDIR(conn, name, mode)) != 0) { + if (SMB_VFS_MKDIR(conn, name, mode) != 0) { return map_nt_error_from_unix(errno); } diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c index 52660da2ffe..58756a0b5a6 100644 --- a/source/smbd/pipes.c +++ b/source/smbd/pipes.c @@ -300,7 +300,5 @@ int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf) return ERROR_DOS(ERRDOS,ERRbadfid); } - /* TODO: REMOVE PIPE FROM DB */ - return(outsize); } diff --git a/source/smbd/process.c b/source/smbd/process.c index 14941e64990..836801ba82c 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -1148,6 +1148,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) unsigned smb_off2 = SVAL(inbuf,smb_vwv1); char *inbuf2, *outbuf2; int outsize2; + int new_size; char inbuf_saved[smb_wct]; char outbuf_saved[smb_wct]; int outsize = smb_len(outbuf) + 4; @@ -1198,6 +1199,20 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) /* create the in buffer */ SCVAL(inbuf2,smb_com,smb_com2); + /* work out the new size for the in buffer. */ + new_size = size - (inbuf2 - inbuf); + if (new_size < 0) { + DEBUG(0,("chain_reply: chain packet size incorrect (orig size = %d, " + "offset = %d)\n", + size, + (inbuf2 - inbuf) )); + exit_server_cleanly("Bad chained packet"); + return(-1); + } + + /* And set it in the header. */ + smb_setlen(inbuf2, new_size); + /* create the out buffer */ construct_reply_common(inbuf2, outbuf2); @@ -1205,7 +1220,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) show_msg(inbuf2); /* process the request */ - outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size, + outsize2 = switch_message(smb_com2,inbuf2,outbuf2,new_size, bufsize-chain_size); /* copy the new reply and request headers over the old ones, but @@ -1219,8 +1234,10 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) { int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf); - if (ofs < 0) ofs = 0; - memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs); + if (ofs < 0) { + ofs = 0; + } + memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs); } return outsize2; diff --git a/source/smbd/reply.c b/source/smbd/reply.c index c48bebb0c6c..14b16e1ae23 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -44,9 +44,12 @@ extern BOOL global_encrypted_passwords_negotiated; set. ****************************************************************************/ +/* Custom version for processing POSIX paths. */ +#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\')) + NTSTATUS check_path_syntax_internal(pstring destname, const pstring srcname, - BOOL windows_path, + BOOL posix_path, BOOL *p_last_component_contains_wcard) { char *d = destname; @@ -57,12 +60,12 @@ NTSTATUS check_path_syntax_internal(pstring destname, *p_last_component_contains_wcard = False; while (*s) { - if (IS_DIRECTORY_SEP(*s)) { + if (IS_PATH_SEP(*s,posix_path)) { /* * Safe to assume is not the second part of a mb char as this is handled below. */ /* Eat multiple '/' or '\\' */ - while (IS_DIRECTORY_SEP(*s)) { + while (IS_PATH_SEP(*s,posix_path)) { s++; } if ((d != destname) && (*s != '\0')) { @@ -77,7 +80,7 @@ NTSTATUS check_path_syntax_internal(pstring destname, } if (start_of_name_component) { - if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) { + if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) { /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */ /* @@ -107,8 +110,8 @@ NTSTATUS check_path_syntax_internal(pstring destname, /* We're still at the start of a name component, just the previous one. */ continue; - } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) { - if (!windows_path) { + } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) { + if (posix_path) { /* Eat the '.' */ s++; continue; @@ -118,7 +121,7 @@ NTSTATUS check_path_syntax_internal(pstring destname, } if (!(*s & 0x80)) { - if (windows_path) { + if (!posix_path) { if (*s <= 0x1f) { return NT_STATUS_OBJECT_NAME_INVALID; } @@ -176,7 +179,7 @@ NTSTATUS check_path_syntax_internal(pstring destname, NTSTATUS check_path_syntax(pstring destname, const pstring srcname) { BOOL ignore; - return check_path_syntax_internal(destname, srcname, True, &ignore); + return check_path_syntax_internal(destname, srcname, False, &ignore); } /**************************************************************************** @@ -187,7 +190,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname) NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard) { - return check_path_syntax_internal(destname, srcname, True, p_contains_wcard); + return check_path_syntax_internal(destname, srcname, False, p_contains_wcard); } /**************************************************************************** @@ -196,10 +199,10 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL * set (a safe assumption). ****************************************************************************/ -static NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname) +NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname) { BOOL ignore; - return check_path_syntax_internal(destname, srcname, False, &ignore); + return check_path_syntax_internal(destname, srcname, True, &ignore); } /**************************************************************************** @@ -224,6 +227,16 @@ size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t de *contains_wcard = False; + if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) { + /* + * For a DFS path the function parse_dfs_path() + * will do the path processing, just make a copy. + */ + pstrcpy(dest, tmppath); + *err = NT_STATUS_OK; + return ret; + } + if (lp_posix_pathnames()) { *err = check_path_syntax_posix(dest, tmppath); } else { @@ -251,6 +264,17 @@ size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len } else { ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags); } + + if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) { + /* + * For a DFS path the function parse_dfs_path() + * will do the path processing, just make a copy. + */ + pstrcpy(dest, tmppath); + *err = NT_STATUS_OK; + return ret; + } + if (lp_posix_pathnames()) { *err = check_path_syntax_posix(dest, tmppath); } else { @@ -631,7 +655,14 @@ int reply_checkpath(connection_struct *conn, char *inbuf,char *outbuf, int dum_s return ERROR_NT(status); } - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + END_PROFILE(SMBcheckpath); + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + goto path_err; + } DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(inbuf,smb_vwv0))); @@ -710,7 +741,14 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(status); } - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBgetatr); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } /* dos smetimes asks for a stat of "" - it returns a "hidden directory" under WfWg - weird! */ @@ -789,7 +827,14 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(status); } - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBsetatr); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, fname, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -797,6 +842,12 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(status); } + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBsetatr); + return ERROR_NT(status); + } + if (fname[0] == '.' && fname[1] == '\0') { /* * Not sure here is the right place to catch this @@ -806,12 +857,6 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(NT_STATUS_ACCESS_DENIED); } - status = check_name(conn, fname); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBsetatr); - return ERROR_NT(status); - } - mode = SVAL(inbuf,smb_vwv0); mtime = srv_make_unix_date3(inbuf+smb_vwv1); @@ -827,7 +872,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } } - if (!set_filetime(conn,fname,mtime)) { + if (!set_filetime(conn,fname,convert_time_t_to_timespec(mtime))) { END_PROFILE(SMBsetatr); return UNIXERROR(ERRDOS, ERRnoaccess); } @@ -944,7 +989,14 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(nt_status); } - RESOLVE_DFSPATH_WCARD(path, conn, inbuf, outbuf); + nt_status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, path, &mask_contains_wcard); + if (!NT_STATUS_IS_OK(nt_status)) { + END_PROFILE(SMBsearch); + if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(nt_status); + } p++; status_len = SVAL(p, 0); @@ -954,16 +1006,13 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (status_len == 0) { SMB_STRUCT_STAT sbuf; - pstring dir2; pstrcpy(directory,path); - pstrcpy(dir2,path); nt_status = unix_convert(conn, directory, True, NULL, &sbuf); if (!NT_STATUS_IS_OK(nt_status)) { END_PROFILE(SMBsearch); return ERROR_NT(nt_status); } - unix_format(dir2); nt_status = check_name(conn, directory); if (!NT_STATUS_IS_OK(nt_status)) { @@ -971,23 +1020,16 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(nt_status); } - p = strrchr_m(dir2,'/'); - if (p == NULL) { - pstrcpy(mask,dir2); - *dir2 = 0; - } else { - *p = 0; - pstrcpy(mask,p+1); - } - p = strrchr_m(directory,'/'); if (!p) { - *directory = 0; + pstrcpy(mask,directory); + pstrcpy(directory,"."); } else { *p = 0; + pstrcpy(mask,p+1); } - if (strlen(directory) == 0) { + if (*directory == '\0') { pstrcpy(directory,"."); } memset((char *)status,'\0',21); @@ -1007,6 +1049,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } string_set(&conn->dirpath,dptr_path(dptr_num)); pstrcpy(mask, dptr_wcard(dptr_num)); + /* + * For a 'continue' search we have no string. So + * check from the initial saved string. + */ + mask_contains_wcard = ms_has_wild(mask); } p = smb_buf(outbuf) + 3; @@ -1202,7 +1249,14 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBopen); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, fname, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -1210,6 +1264,12 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBopen); + return ERROR_NT(status); + } + if (!map_open_params_to_ntcreate(fname, deny_mode, OPENX_FILE_EXISTS_OPEN, &access_mask, &share_mode, &create_disposition, &create_options)) { END_PROFILE(SMBopen); @@ -1320,7 +1380,14 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return ERROR_NT(status); } - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBopenX); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, fname, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -1328,6 +1395,12 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return ERROR_NT(status); } + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBopenX); + return ERROR_NT(status); + } + if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun, &access_mask, &share_mode, @@ -1470,7 +1543,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int com; int outsize = 0; uint32 fattr = SVAL(inbuf,smb_vwv0); - struct utimbuf times; + struct timespec ts[2]; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); SMB_STRUCT_STAT sbuf; @@ -1484,7 +1557,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, com = SVAL(inbuf,smb_com); - times.modtime = srv_make_unix_date3(inbuf + smb_vwv1); + ts[1] = convert_time_t_to_timespec(srv_make_unix_date3(inbuf + smb_vwv1)); /* mtime. */ srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { @@ -1492,7 +1565,14 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcreate); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, fname, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -1500,6 +1580,12 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcreate); + return ERROR_NT(status); + } + if (fattr & aVOLID) { DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname)); } @@ -1531,8 +1617,8 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } - times.actime = sbuf.st_atime; - file_utime(conn, fname, ×); + ts[0] = get_atimespec(&sbuf); /* atime. */ + file_ntimes(conn, fname, ts); outsize = set_message(outbuf,1,0,True); SSVAL(outbuf,smb_vwv0,fsp->fnum); @@ -1582,13 +1668,26 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstrcat(fname,"TMXXXXXX"); } - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBctemp); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, fname, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBctemp); return ERROR_NT(status); } + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBctemp); + return ERROR_NT(status); + } tmpfd = smb_mkstemp(fname); if (tmpfd == -1) { @@ -1858,6 +1957,12 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, if (dirtype == 0) { dirtype = FILE_ATTRIBUTE_NORMAL; } + + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = can_delete(conn,directory,dirtype,can_defer); if (!NT_STATUS_IS_OK(status)) { return status; @@ -1920,6 +2025,13 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, } slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + CloseDir(dir_hnd); + return status; + } + status = can_delete(conn, fname, dirtype, can_defer); if (!NT_STATUS_IS_OK(status)) { continue; @@ -1966,8 +2078,15 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size END_PROFILE(SMBunlink); return ERROR_NT(status); } - - RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf); + + status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &path_contains_wcard); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBunlink); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } DEBUG(3,("reply_unlink : %s\n",name)); @@ -3109,7 +3228,6 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, { NTSTATUS status = NT_STATUS_OK; int outsize = 0; - time_t mtime; files_struct *fsp = NULL; START_PROFILE(SMBclose); @@ -3151,8 +3269,8 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, * Take care of any time sent in the close. */ - mtime = srv_make_unix_date3(inbuf+smb_vwv1); - fsp_set_pending_modtime(fsp, mtime); + fsp_set_pending_modtime(fsp, + convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv1))); /* * close_file() returns the unix errno if an error @@ -3185,7 +3303,7 @@ int reply_writeclose(connection_struct *conn, NTSTATUS close_status = NT_STATUS_OK; SMB_OFF_T startpos; char *data; - time_t mtime; + struct timespec mtime; files_struct *fsp = file_fsp(inbuf,smb_vwv0); START_PROFILE(SMBwriteclose); @@ -3196,7 +3314,7 @@ int reply_writeclose(connection_struct *conn, numtowrite = SVAL(inbuf,smb_vwv1); startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); - mtime = srv_make_unix_date3(inbuf+smb_vwv4); + mtime = convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv4)); data = smb_buf(inbuf) + 1; if (numtowrite && is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) { @@ -3206,7 +3324,7 @@ int reply_writeclose(connection_struct *conn, nwritten = write_file(fsp,data,startpos,numtowrite); - set_filetime(conn, fsp->fsp_name,mtime); + set_filetime(conn, fsp->fsp_name, mtime); /* * More insanity. W2K only closes the file if writelen > 0. @@ -3598,7 +3716,14 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } - RESOLVE_DFSPATH(directory, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBmkdir); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, directory, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -3606,6 +3731,12 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBmkdir); + return ERROR_NT(status); + } + status = create_directory(conn, directory); DEBUG(5, ("create_directory returned %s\n", nt_errstr(status))); @@ -3810,7 +3941,14 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } - RESOLVE_DFSPATH(directory, conn, inbuf, outbuf) + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBrmdir); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, directory, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -3854,7 +3992,6 @@ static BOOL resolve_wildcards(const char *name1, char *name2) char *p,*p2, *pname1, *pname2; int available_space, actual_space; - pname1 = strrchr_m(name1,'/'); pname2 = strrchr_m(name2,'/'); @@ -4008,6 +4145,11 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstrin return status; } + status = check_name(conn, newname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* Ensure newname contains a '/' */ if(strrchr_m(newname,'/') == 0) { pstring tmpstr; @@ -4152,9 +4294,13 @@ static void notify_rename(connection_struct *conn, BOOL is_dir, code. ****************************************************************************/ -NTSTATUS rename_internals(connection_struct *conn, pstring name, - pstring newname, uint32 attrs, - BOOL replace_if_exists, BOOL has_wild) +NTSTATUS rename_internals(connection_struct *conn, + pstring name, + pstring newname, + uint32 attrs, + BOOL replace_if_exists, + BOOL src_has_wild, + BOOL dest_has_wild) { pstring directory; pstring mask; @@ -4165,20 +4311,22 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name, NTSTATUS status = NT_STATUS_OK; SMB_STRUCT_STAT sbuf1, sbuf2; struct share_mode_lock *lck = NULL; + struct smb_Dir *dir_hnd = NULL; + const char *dname; + long offset = 0; + pstring destname; *directory = *mask = 0; ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); - status = unix_convert(conn, name, has_wild, last_component_src, - &sbuf1); + status = unix_convert(conn, name, src_has_wild, last_component_src, &sbuf1); if (!NT_STATUS_IS_OK(status)) { return status; } - status = unix_convert(conn, newname, True, last_component_dest, - &sbuf2); + status = unix_convert(conn, newname, dest_has_wild, last_component_dest, &sbuf2); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -4212,10 +4360,11 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name, * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) + if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); + } - if (!has_wild) { + if (!src_has_wild) { /* * No wildcards - just process the one file. */ @@ -4242,6 +4391,21 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name, conn->short_case_preserve, directory, newname, last_component_dest, is_short_name)); + /* Ensure the source name is valid for us to access. */ + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* The dest name still may have wildcards. */ + if (dest_has_wild) { + if (!resolve_wildcards(directory,newname)) { + DEBUG(6, ("rename_internals: resolve_wildcards %s %s failed\n", + directory,newname)); + return NT_STATUS_NO_MEMORY; + } + } + /* * Check for special case with case preserving and not * case sensitive, if directory and newname are identical, @@ -4276,8 +4440,12 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name, } } - resolve_wildcards(directory,newname); - + /* Ensure the dest name is valid for us to access. */ + status = check_name(conn, newname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* * The source object must exist. */ @@ -4369,136 +4537,130 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name, nt_errstr(status), directory,newname)); return status; - } else { - /* - * Wildcards - process each file that matches. - */ - struct smb_Dir *dir_hnd = NULL; - const char *dname; - long offset = 0; - pstring destname; - - if (strequal(mask,"????????.???")) - pstrcpy(mask,"*"); + } + + /* + * Wildcards - process each file that matches. + */ + if (strequal(mask,"????????.???")) { + pstrcpy(mask,"*"); + } - status = check_name(conn, directory); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - dir_hnd = OpenDir(conn, directory, mask, attrs); - if (dir_hnd == NULL) { - return map_nt_error_from_unix(errno); - } + dir_hnd = OpenDir(conn, directory, mask, attrs); + if (dir_hnd == NULL) { + return map_nt_error_from_unix(errno); + } - status = NT_STATUS_NO_SUCH_FILE; - /* - * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - * - gentest fix. JRA - */ + status = NT_STATUS_NO_SUCH_FILE; + /* + * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + * - gentest fix. JRA + */ - while ((dname = ReadDirName(dir_hnd, &offset))) { - pstring fname; - BOOL sysdir_entry = False; + while ((dname = ReadDirName(dir_hnd, &offset))) { + pstring fname; + BOOL sysdir_entry = False; - pstrcpy(fname,dname); + pstrcpy(fname,dname); - /* Quick check for "." and ".." */ - if (fname[0] == '.') { - if (!fname[1] - || (fname[1] == '.' && !fname[2])) { - if (attrs & aDIR) { - sysdir_entry = True; - } else { - continue; - } + /* Quick check for "." and ".." */ + if (fname[0] == '.') { + if (!fname[1] || (fname[1] == '.' && !fname[2])) { + if (attrs & aDIR) { + sysdir_entry = True; + } else { + continue; } } + } - if (!is_visible_file(conn, directory, dname, &sbuf1, - False)) { - continue; - } + if (!is_visible_file(conn, directory, dname, &sbuf1, False)) { + continue; + } - if(!mask_match(fname, mask, conn->case_sensitive)) { - continue; - } + if(!mask_match(fname, mask, conn->case_sensitive)) { + continue; + } - if (sysdir_entry) { - status = NT_STATUS_OBJECT_NAME_INVALID; - break; - } + if (sysdir_entry) { + status = NT_STATUS_OBJECT_NAME_INVALID; + break; + } - status = NT_STATUS_ACCESS_DENIED; - slprintf(fname, sizeof(fname)-1, "%s/%s", directory, - dname); - if (!vfs_object_exist(conn, fname, &sbuf1)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - DEBUG(6, ("rename %s failed. Error %s\n", - fname, nt_errstr(status))); - continue; - } - status = can_rename(conn,fname,attrs,&sbuf1); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(6, ("rename %s refused\n", fname)); - continue; - } - pstrcpy(destname,newname); + status = NT_STATUS_ACCESS_DENIED; + slprintf(fname, sizeof(fname)-1, "%s/%s", directory, dname); + + /* Ensure the source name is valid for us to access. */ + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!vfs_object_exist(conn, fname, &sbuf1)) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + DEBUG(6, ("rename %s failed. Error %s\n", + fname, nt_errstr(status))); + continue; + } + status = can_rename(conn,fname,attrs,&sbuf1); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(6, ("rename %s refused\n", fname)); + continue; + } + pstrcpy(destname,newname); - if (!resolve_wildcards(fname,destname)) { - DEBUG(6, ("resolve_wildcards %s %s failed\n", - fname, destname)); - continue; - } + if (!resolve_wildcards(fname,destname)) { + DEBUG(6, ("resolve_wildcards %s %s failed\n", + fname, destname)); + continue; + } - if (strcsequal(fname,destname)) { - rename_open_files(conn, NULL, sbuf1.st_dev, - sbuf1.st_ino, newname); - DEBUG(3,("rename_internals: identical names " - "in wildcard rename %s - success\n", - fname)); - count++; - status = NT_STATUS_OK; - continue; - } + /* Ensure the dest name is valid for us to access. */ + status = check_name(conn, destname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - if (!replace_if_exists - && vfs_file_exist(conn,destname, NULL)) { - DEBUG(6,("file_exist %s\n", destname)); - status = NT_STATUS_OBJECT_NAME_COLLISION; - continue; - } + if (strcsequal(fname,destname)) { + rename_open_files(conn, NULL, sbuf1.st_dev, + sbuf1.st_ino, newname); + DEBUG(3,("rename_internals: identical names " + "in wildcard rename %s - success\n", + fname)); + count++; + status = NT_STATUS_OK; + continue; + } + + if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) { + DEBUG(6,("file_exist %s\n", destname)); + status = NT_STATUS_OBJECT_NAME_COLLISION; + continue; + } - if (rename_path_prefix_equal(fname, destname)) { - return NT_STATUS_SHARING_VIOLATION; - } + if (rename_path_prefix_equal(fname, destname)) { + return NT_STATUS_SHARING_VIOLATION; + } - lck = get_share_mode_lock(NULL, sbuf1.st_dev, - sbuf1.st_ino, NULL, NULL); + lck = get_share_mode_lock(NULL, sbuf1.st_dev, + sbuf1.st_ino, NULL, NULL); - if (!SMB_VFS_RENAME(conn,fname,destname)) { - rename_open_files(conn, lck, sbuf1.st_dev, - sbuf1.st_ino, newname); - count++; - status = NT_STATUS_OK; - } - TALLOC_FREE(lck); - DEBUG(3,("rename_internals: doing rename on %s -> " - "%s\n",fname,destname)); + if (!SMB_VFS_RENAME(conn,fname,destname)) { + rename_open_files(conn, lck, sbuf1.st_dev, + sbuf1.st_ino, newname); + count++; + status = NT_STATUS_OK; } - CloseDir(dir_hnd); + TALLOC_FREE(lck); + DEBUG(3,("rename_internals: doing rename on %s -> " + "%s\n",fname,destname)); } - -#if 0 - /* Don't think needed any more - JRA. */ - if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) { - if (!rcdest && bad_path_dest) { - if (ms_has_wild(last_component_dest)) - return NT_STATUS_OBJECT_NAME_INVALID; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - } -#endif + CloseDir(dir_hnd); if (count == 0 && NT_STATUS_IS_OK(status)) { status = map_nt_error_from_unix(errno); @@ -4520,30 +4682,45 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, char *p; uint32 attrs = SVAL(inbuf,smb_vwv0); NTSTATUS status; - BOOL path1_contains_wcard = False; - BOOL path2_contains_wcard = False; + BOOL src_has_wcard = False; + BOOL dest_has_wcard = False; START_PROFILE(SMBmv); p = smb_buf(inbuf) + 1; - p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &path1_contains_wcard); + p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &src_has_wcard); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmv); return ERROR_NT(status); } p++; - p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path2_contains_wcard); + p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmv); return ERROR_NT(status); } - RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf); - RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf); + status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &src_has_wcard); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBmv); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } + + status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBmv); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); - status = rename_internals(conn, name, newname, attrs, False, path1_contains_wcard); + status = rename_internals(conn, name, newname, attrs, False, src_has_wcard, dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmv); if (open_was_deferred(SVAL(inbuf,smb_mid))) { @@ -4567,8 +4744,12 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, * TODO: check error codes on all callers */ -NTSTATUS copy_file(char *src, char *dest1,connection_struct *conn, int ofun, - int count, BOOL target_is_directory) +NTSTATUS copy_file(connection_struct *conn, + char *src, + char *dest1, + int ofun, + int count, + BOOL target_is_directory) { SMB_STRUCT_STAT src_sbuf, sbuf2; SMB_OFF_T ret=-1; @@ -4653,7 +4834,7 @@ NTSTATUS copy_file(char *src, char *dest1,connection_struct *conn, int ofun, close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - fsp_set_pending_modtime( fsp2, src_sbuf.st_mtime); + fsp_set_pending_modtime( fsp2, get_mtimespec(&src_sbuf)); /* * As we are opening fsp1 read-only we only expect @@ -4688,14 +4869,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int count=0; int error = ERRnoaccess; int err = 0; - BOOL has_wild; - BOOL exists=False; int tid2 = SVAL(inbuf,smb_vwv0); int ofun = SVAL(inbuf,smb_vwv1); int flags = SVAL(inbuf,smb_vwv2); BOOL target_is_directory=False; - BOOL path_contains_wcard1 = False; - BOOL path_contains_wcard2 = False; + BOOL source_has_wild = False; + BOOL dest_has_wild = False; SMB_STRUCT_STAT sbuf1, sbuf2; NTSTATUS status; START_PROFILE(SMBcopy); @@ -4703,12 +4882,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, *directory = *mask = 0; p = smb_buf(inbuf); - p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &path_contains_wcard1); + p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &source_has_wild); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcopy); return ERROR_NT(status); } - p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path_contains_wcard2); + p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcopy); return ERROR_NT(status); @@ -4723,16 +4902,31 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_DOS(ERRSRV,ERRinvdevice); } - RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf); - RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf); + status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &source_has_wild); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcopy); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } - status = unix_convert(conn, name, path_contains_wcard1, NULL, &sbuf1); + status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcopy); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } return ERROR_NT(status); } - status = unix_convert(conn, newname, path_contains_wcard2, NULL, &sbuf2); + status = unix_convert(conn, name, source_has_wild, NULL, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcopy); + return ERROR_NT(status); + } + + status = unix_convert(conn, newname, dest_has_wild, NULL, &sbuf2); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcopy); return ERROR_NT(status); @@ -4776,25 +4970,38 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) + if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); + } - has_wild = path_contains_wcard1; - - if (!has_wild) { + if (!source_has_wild) { pstrcat(directory,"/"); pstrcat(directory,mask); - if (resolve_wildcards(directory,newname) - && NT_STATUS_IS_OK(status = copy_file( - directory,newname,conn,ofun, - count,target_is_directory))) - count++; - if(!count && !NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBcopy); + if (dest_has_wild) { + if (!resolve_wildcards(directory,newname)) { + END_PROFILE(SMBcopy); + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + } + + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); + } + + status = check_name(conn, newname); + if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } - if (!count) { - exists = vfs_file_exist(conn,directory,NULL); + + status = copy_file(conn,directory,newname,ofun, + count,target_is_directory); + + if(!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcopy); + return ERROR_NT(status); + } else { + count++; } } else { struct smb_Dir *dir_hnd = NULL; @@ -4833,13 +5040,27 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, error = ERRnoaccess; slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); pstrcpy(destname,newname); - if (resolve_wildcards(fname,destname) && - NT_STATUS_IS_OK(status = copy_file( - fname,destname,conn,ofun, - count,target_is_directory))) { + if (!resolve_wildcards(fname,destname)) { + continue; + } + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); + } + + status = check_name(conn, destname); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); + } + + DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname)); + + status = copy_file(conn,fname,destname,ofun, + count,target_is_directory); + if (NT_STATUS_IS_OK(status)) { count++; } - DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname)); } CloseDir(dir_hnd); } @@ -4888,7 +5109,14 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(status); } - RESOLVE_DFSPATH(newdir, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newdir); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(pathworks_setdir); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } if (strlen(newdir) != 0) { if (!vfs_directory_exist(conn,newdir,NULL)) { @@ -5440,7 +5668,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length, int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { - struct utimbuf unix_times; + struct timespec ts[2]; int outsize = 0; files_struct *fsp = file_fsp(inbuf,smb_vwv0); START_PROFILE(SMBsetattrE); @@ -5457,15 +5685,15 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, * time as UNIX can't set this. */ - unix_times.actime = srv_make_unix_date2(inbuf+smb_vwv3); - unix_times.modtime = srv_make_unix_date2(inbuf+smb_vwv5); + ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv3)); /* atime. */ + ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv5)); /* mtime. */ /* * Patch from Ray Frush <frush@engr.colostate.edu> * Sometimes times are sent as zero - ignore them. */ - if (null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) { + if (null_timespec(ts[0]) && null_timespec(ts[1])) { /* Ignore request */ if( DEBUGLVL( 3 ) ) { dbgtext( "reply_setattrE fnum=%d ", fsp->fnum); @@ -5473,20 +5701,22 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, } END_PROFILE(SMBsetattrE); return(outsize); - } else if (!null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) { + } else if (!null_timespec(ts[0]) && null_timespec(ts[1])) { /* set modify time = to access time if modify time was unset */ - unix_times.modtime = unix_times.actime; + ts[1] = ts[0]; } /* Set the date on this file */ /* Should we set pending modtime here ? JRA */ - if(file_utime(conn, fsp->fsp_name, &unix_times)) { + if(file_ntimes(conn, fsp->fsp_name, ts)) { END_PROFILE(SMBsetattrE); return ERROR_DOS(ERRDOS,ERRnoaccess); } - DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n", - fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) ); + DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n", + fsp->fnum, + (unsigned int)ts[0].tv_sec, + (unsigned int)ts[1].tv_sec)); END_PROFILE(SMBsetattrE); return(outsize); diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c index 7a5f8be47ff..ff1b2821cca 100644 --- a/source/smbd/sesssetup.c +++ b/source/smbd/sesssetup.c @@ -158,13 +158,76 @@ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) #ifdef HAVE_KRB5 + +#if 0 +/* Experiment that failed. See "only happens with a KDC" comment below. */ +/**************************************************************************** + Cerate a clock skew error blob for a Windows client. +****************************************************************************/ + +static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out) +{ + krb5_context context = NULL; + krb5_error_code kerr = 0; + krb5_data reply; + krb5_principal host_princ = NULL; + char *host_princ_s = NULL; + BOOL ret = False; + + *pblob_out = data_blob(NULL,0); + + initialize_krb5_error_table(); + kerr = krb5_init_context(&context); + if (kerr) { + return False; + } + /* Create server principal. */ + asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm()); + if (!host_princ_s) { + goto out; + } + strlower_m(host_princ_s); + + kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ); + if (kerr) { + DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n", + host_princ_s, error_message(kerr) )); + goto out; + } + + kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply); + if (kerr) { + DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n", + error_message(kerr) )); + goto out; + } + + *pblob_out = data_blob(reply.data, reply.length); + kerberos_free_data_contents(context,&reply); + ret = True; + + out: + + if (host_princ_s) { + SAFE_FREE(host_princ_s); + } + if (host_princ) { + krb5_free_principal(context, host_princ); + } + krb5_free_context(context); + return ret; +} +#endif + /**************************************************************************** -reply to a session setup spnego negotiate packet for kerberos + Reply to a session setup spnego negotiate packet for kerberos. ****************************************************************************/ + static int reply_spnego_kerberos(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - DATA_BLOB *secblob) + DATA_BLOB *secblob, + BOOL *p_invalidate_vuid) { TALLOC_CTX *mem_ctx; DATA_BLOB ticket; @@ -191,9 +254,13 @@ static int reply_spnego_kerberos(connection_struct *conn, ZERO_STRUCT(ap_rep_wrapped); ZERO_STRUCT(response); + /* Normally we will always invalidate the intermediate vuid. */ + *p_invalidate_vuid = True; + mem_ctx = talloc_init("reply_spnego_kerberos"); - if (mem_ctx == NULL) + if (mem_ctx == NULL) { return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY)); + } if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) { talloc_destroy(mem_ctx); @@ -205,9 +272,50 @@ static int reply_spnego_kerberos(connection_struct *conn, data_blob_free(&ticket); if (!NT_STATUS_IS_OK(ret)) { - DEBUG(1,("Failed to verify incoming ticket!\n")); +#if 0 + /* Experiment that failed. See "only happens with a KDC" comment below. */ + + if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) { + + /* + * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED + * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded + * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its + * clock and continues rather than giving an error. JRA. + * -- Looks like this only happens with a KDC. JRA. + */ + + BOOL ok = make_krb5_skew_error(&ap_rep); + if (!ok) { + talloc_destroy(mem_ctx); + return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); + } + ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR); + response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD); + reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED); + + /* + * In this one case we don't invalidate the intermediate vuid. + * as we're expecting the client to re-use it for the next + * sessionsetupX packet. JRA. + */ + + *p_invalidate_vuid = False; + + data_blob_free(&ap_rep); + data_blob_free(&ap_rep_wrapped); + data_blob_free(&response); + talloc_destroy(mem_ctx); + return -1; /* already replied */ + } +#else + if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) { + ret = NT_STATUS_LOGON_FAILURE; + } +#endif + DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret))); talloc_destroy(mem_ctx); - return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); + return ERROR_NT(nt_status_squash(ret)); } DEBUG(3,("Ticket name is [%s]\n", client)); @@ -523,32 +631,19 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out } /**************************************************************************** - Reply to a session setup spnego negotiate packet. + Is this a krb5 mechanism ? ****************************************************************************/ -static int reply_spnego_negotiate(connection_struct *conn, - char *inbuf, - char *outbuf, - uint16 vuid, - int length, int bufsize, - DATA_BLOB blob1, - AUTH_NTLMSSP_STATE **auth_ntlmssp_state) +static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5) { char *OIDs[ASN1_MAX_OIDS]; - DATA_BLOB secblob; int i; - DATA_BLOB chal; -#ifdef HAVE_KRB5 - BOOL got_kerberos_mechanism = False; -#endif - NTSTATUS nt_status; - /* parse out the OIDs and the first sec blob */ - if (!parse_negTokenTarg(blob1, OIDs, &secblob)) { - /* Kill the intermediate vuid */ - invalidate_vuid(vuid); + *p_is_krb5 = False; - return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); + /* parse out the OIDs and the first sec blob */ + if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) { + return NT_STATUS_LOGON_FAILURE; } /* only look at the first OID for determining the mechToken -- @@ -564,24 +659,53 @@ static int reply_spnego_negotiate(connection_struct *conn, #ifdef HAVE_KRB5 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 || strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) { - got_kerberos_mechanism = True; + *p_is_krb5 = True; } #endif for (i=0;OIDs[i];i++) { - DEBUG(3,("Got OID %s\n", OIDs[i])); + DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i])); free(OIDs[i]); } - DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length)); + return NT_STATUS_OK; +} + +/**************************************************************************** + Reply to a session setup spnego negotiate packet. +****************************************************************************/ + +static int reply_spnego_negotiate(connection_struct *conn, + char *inbuf, + char *outbuf, + uint16 vuid, + int length, int bufsize, + DATA_BLOB blob1, + AUTH_NTLMSSP_STATE **auth_ntlmssp_state) +{ + DATA_BLOB secblob; + DATA_BLOB chal; + BOOL got_kerberos_mechanism = False; + NTSTATUS status; + + status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism); + if (!NT_STATUS_IS_OK(status)) { + /* Kill the intermediate vuid */ + invalidate_vuid(vuid); + return ERROR_NT(nt_status_squash(status)); + } + + DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length)); #ifdef HAVE_KRB5 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) { + BOOL destroy_vuid = True; int ret = reply_spnego_kerberos(conn, inbuf, outbuf, - length, bufsize, &secblob); + length, bufsize, &secblob, &destroy_vuid); data_blob_free(&secblob); - /* Kill the intermediate vuid */ - invalidate_vuid(vuid); - + if (destroy_vuid) { + /* Kill the intermediate vuid */ + invalidate_vuid(vuid); + } return ret; } #endif @@ -590,28 +714,27 @@ static int reply_spnego_negotiate(connection_struct *conn, auth_ntlmssp_end(auth_ntlmssp_state); } - nt_status = auth_ntlmssp_start(auth_ntlmssp_state); - if (!NT_STATUS_IS_OK(nt_status)) { + status = auth_ntlmssp_start(auth_ntlmssp_state); + if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); - - return ERROR_NT(nt_status_squash(nt_status)); + return ERROR_NT(nt_status_squash(status)); } - nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, + status = auth_ntlmssp_update(*auth_ntlmssp_state, secblob, &chal); data_blob_free(&secblob); reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state, - &chal, nt_status, True); + &chal, status, True); data_blob_free(&chal); /* already replied */ return -1; } - + /**************************************************************************** Reply to a session setup spnego auth packet. ****************************************************************************/ @@ -622,8 +745,10 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, DATA_BLOB blob1, AUTH_NTLMSSP_STATE **auth_ntlmssp_state) { - DATA_BLOB auth, auth_reply; - NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; + DATA_BLOB auth = data_blob(NULL,0); + DATA_BLOB auth_reply = data_blob(NULL,0); + DATA_BLOB secblob = data_blob(NULL,0); + NTSTATUS status = NT_STATUS_INVALID_PARAMETER; if (!spnego_parse_auth(blob1, &auth)) { #if 0 @@ -634,6 +759,33 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } + + if (auth.data[0] == ASN1_APPLICATION(0)) { + /* Might be a second negTokenTarg packet */ + + BOOL got_krb5_mechanism = False; + status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism); + if (NT_STATUS_IS_OK(status)) { + DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length)); +#ifdef HAVE_KRB5 + if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) { + BOOL destroy_vuid = True; + int ret = reply_spnego_kerberos(conn, inbuf, outbuf, + length, bufsize, &secblob, &destroy_vuid); + data_blob_free(&secblob); + data_blob_free(&auth); + if (destroy_vuid) { + /* Kill the intermediate vuid */ + invalidate_vuid(vuid); + } + return ret; + } +#endif + } + } + + /* If we get here it wasn't a negTokenTarg auth packet. */ + data_blob_free(&secblob); if (!*auth_ntlmssp_state) { /* Kill the intermediate vuid */ @@ -643,14 +795,14 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } - nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, + status = auth_ntlmssp_update(*auth_ntlmssp_state, auth, &auth_reply); data_blob_free(&auth); reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state, - &auth_reply, nt_status, True); + &auth_reply, status, True); data_blob_free(&auth_reply); diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 5bbd618231b..deb5db1bafe 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -5,6 +5,7 @@ Copyright (C) Stefan (metze) Metzmacher 2003 Copyright (C) Volker Lendecke 2005 Copyright (C) Steve French 2005 + Copyright (C) James Peach 2007 Extensively modified by Andrew Tridgell, 1995 @@ -34,6 +35,16 @@ extern struct current_user current_user; #define get_file_size(sbuf) ((sbuf).st_size) #define DIR_ENTRY_SAFETY_MARGIN 4096 +static char *store_file_unix_basic(connection_struct *conn, + char *pdata, + files_struct *fsp, + const SMB_STRUCT_STAT *psbuf); + +static char *store_file_unix_basic_info2(connection_struct *conn, + char *pdata, + files_struct *fsp, + const SMB_STRUCT_STAT *psbuf); + /******************************************************************** Roundup a value to the nearest allocation roundup size boundary. Only do this for Windows clients. @@ -56,7 +67,7 @@ SMB_BIG_UINT smb_roundup(connection_struct *conn, SMB_BIG_UINT val) account sparse files. ********************************************************************/ -SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, SMB_STRUCT_STAT *sbuf) +SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *sbuf) { SMB_BIG_UINT ret; @@ -1191,15 +1202,17 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, continue; } } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) { + pstring link_target; /* Needed to show the msdfs symlinks as * directories */ if(lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) && - ((ms_dfs_link = is_msdfs_link(NULL,conn, pathreal, NULL, NULL, &sbuf)) == True)) { - - DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal)); + ((ms_dfs_link = is_msdfs_link(conn, pathreal, link_target, &sbuf)) == True)) { + DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s " + "as a directory\n", + pathreal)); sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; } else { @@ -1578,51 +1591,21 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, /* CIFS UNIX Extension. */ case SMB_FIND_FILE_UNIX: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n")); + case SMB_FIND_FILE_UNIX_INFO2: p+= 4; SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ - SOFF_T(p,0,get_file_size(sbuf)); /* File size 64 Bit */ - p+= 8; - - SOFF_T(p,0,get_allocation_size(conn,NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */ - p+= 8; - - put_long_date_timespec(p,get_ctimespec(&sbuf)); /* Inode change Time 64 Bit */ - put_long_date_timespec(p+8,get_atimespec(&sbuf)); /* Last access time 64 Bit */ - put_long_date_timespec(p+16,get_mtimespec(&sbuf)); /* Last modification time 64 Bit */ - p+= 24; - - SIVAL(p,0,sbuf.st_uid); /* user id for the owner */ - SIVAL(p,4,0); - p+= 8; - - SIVAL(p,0,sbuf.st_gid); /* group id of owner */ - SIVAL(p,4,0); - p+= 8; - - SIVAL(p,0,unix_filetype(sbuf.st_mode)); - p+= 4; - - SIVAL(p,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */ - SIVAL(p,4,0); - p+= 8; - - SIVAL(p,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */ - SIVAL(p,4,0); - p+= 8; - - SINO_T_VAL(p,0,(SMB_INO_T)sbuf.st_ino); /* inode number */ - p+= 8; - SIVAL(p,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */ - SIVAL(p,4,0); - p+= 8; - - SIVAL(p,0,sbuf.st_nlink); /* number of hard links */ - SIVAL(p,4,0); - p+= 8; + if (info_level == SMB_FIND_FILE_UNIX) { + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n")); + p = store_file_unix_basic(conn, p, + NULL, &sbuf); + } else { + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n")); + p = store_file_unix_basic_info2(conn, p, + NULL, &sbuf); + } len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE); p += len; @@ -1732,6 +1715,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", case SMB_FIND_ID_BOTH_DIRECTORY_INFO: break; case SMB_FIND_FILE_UNIX: + case SMB_FIND_FILE_UNIX_INFO2: if (!lp_unix_extensions()) { return ERROR_NT(NT_STATUS_INVALID_LEVEL); } @@ -1745,7 +1729,13 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", return ERROR_NT(ntstatus); } - RESOLVE_DFSPATH_WCARD(directory, conn, inbuf, outbuf); + ntstatus = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory, &mask_contains_wcard); + if (!NT_STATUS_IS_OK(ntstatus)) { + if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(ntstatus); + } ntstatus = unix_convert(conn, directory, True, NULL, &sbuf); if (!NT_STATUS_IS_OK(ntstatus)) { @@ -2037,6 +2027,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n", case SMB_FIND_ID_BOTH_DIRECTORY_INFO: break; case SMB_FIND_FILE_UNIX: + case SMB_FIND_FILE_UNIX_INFO2: if (!lp_unix_extensions()) { return ERROR_NT(NT_STATUS_INVALID_LEVEL); } @@ -2232,7 +2223,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf char **pparams, int total_params, char **ppdata, int total_data, unsigned int max_data_bytes) { - char *pdata = *ppdata; + char *pdata; char *params = *pparams; uint16 info_level; int data_len, len; @@ -2530,6 +2521,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned CIFS_UNIX_POSIX_ACLS_CAP| CIFS_UNIX_POSIX_PATHNAMES_CAP| CIFS_UNIX_FCNTL_LOCKS_CAP| + CIFS_UNIX_EXTATTR_CAP| CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP))); break; @@ -2566,6 +2558,114 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned break; } + case SMB_QUERY_POSIX_WHOAMI: + { + uint32_t flags = 0; + uint32_t sid_bytes; + int i; + + if (!lp_unix_extensions()) { + return ERROR_NT(NT_STATUS_INVALID_LEVEL); + } + + if (max_data_bytes < 40) { + return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL); + } + + /* We ARE guest if global_sid_Builtin_Guests is + * in our list of SIDs. + */ + if (nt_token_check_sid(&global_sid_Builtin_Guests, + current_user.nt_user_token)) { + flags |= SMB_WHOAMI_GUEST; + } + + /* We are NOT guest if global_sid_Authenticated_Users + * is in our list of SIDs. + */ + if (nt_token_check_sid(&global_sid_Authenticated_Users, + current_user.nt_user_token)) { + flags &= ~SMB_WHOAMI_GUEST; + } + + /* NOTE: 8 bytes for UID/GID, irrespective of native + * platform size. This matches + * SMB_QUERY_FILE_UNIX_BASIC and friends. + */ + data_len = 4 /* flags */ + + 4 /* flag mask */ + + 8 /* uid */ + + 8 /* gid */ + + 4 /* ngroups */ + + 4 /* num_sids */ + + 4 /* SID bytes */ + + 4 /* pad/reserved */ + + (current_user.ut.ngroups * 8) + /* groups list */ + + (current_user.nt_user_token->num_sids * + SID_MAX_SIZE) + /* SID list */; + + SIVAL(pdata, 0, flags); + SIVAL(pdata, 4, SMB_WHOAMI_MASK); + SBIG_UINT(pdata, 8, (SMB_BIG_UINT)current_user.ut.uid); + SBIG_UINT(pdata, 16, (SMB_BIG_UINT)current_user.ut.gid); + + + if (data_len >= max_data_bytes) { + /* Potential overflow, skip the GIDs and SIDs. */ + + SIVAL(pdata, 24, 0); /* num_groups */ + SIVAL(pdata, 28, 0); /* num_sids */ + SIVAL(pdata, 32, 0); /* num_sid_bytes */ + SIVAL(pdata, 36, 0); /* reserved */ + + data_len = 40; + break; + } + + SIVAL(pdata, 24, current_user.ut.ngroups); + SIVAL(pdata, 28, + current_user.nt_user_token->num_sids); + + /* We walk the SID list twice, but this call is fairly + * infrequent, and I don't expect that it's performance + * sensitive -- jpeach + */ + for (i = 0, sid_bytes = 0; + i < current_user.nt_user_token->num_sids; ++i) { + sid_bytes += + sid_size(¤t_user.nt_user_token->user_sids[i]); + } + + /* SID list byte count */ + SIVAL(pdata, 32, sid_bytes); + + /* 4 bytes pad/reserved - must be zero */ + SIVAL(pdata, 36, 0); + data_len = 40; + + /* GID list */ + for (i = 0; i < current_user.ut.ngroups; ++i) { + SBIG_UINT(pdata, data_len, + (SMB_BIG_UINT)current_user.ut.groups[i]); + data_len += 8; + } + + /* SID list */ + for (i = 0; + i < current_user.nt_user_token->num_sids; ++i) { + int sid_len = + sid_size(¤t_user.nt_user_token->user_sids[i]); + + sid_linearize(pdata + data_len, sid_len, + ¤t_user.nt_user_token->user_sids[i]); + data_len += sid_len; + } + + break; + } + case SMB_MAC_QUERY_FS_INFO: /* * Thursby MAC extension... ONLY on NTFS filesystems @@ -2871,7 +2971,7 @@ static BOOL marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_ static char *store_file_unix_basic(connection_struct *conn, char *pdata, files_struct *fsp, - SMB_STRUCT_STAT *psbuf) + const SMB_STRUCT_STAT *psbuf) { DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n")); DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_mode)); @@ -2920,6 +3020,121 @@ static char *store_file_unix_basic(connection_struct *conn, return pdata; } +/* Forward and reverse mappings from the UNIX_INFO2 file flags field and + * the chflags(2) (or equivalent) flags. + * + * XXX: this really should be behind the VFS interface. To do this, we would + * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field. + * Each VFS module could then implement it's own mapping as appropriate for the + * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS. + */ +static const struct {unsigned stat_fflag; unsigned smb_fflag;} + info2_flags_map[] = +{ +#ifdef UF_NODUMP + { UF_NODUMP, EXT_DO_NOT_BACKUP }, +#endif + +#ifdef UF_IMMUTABLE + { UF_IMMUTABLE, EXT_IMMUTABLE }, +#endif + +#ifdef UF_APPEND + { UF_APPEND, EXT_OPEN_APPEND_ONLY }, +#endif + +#ifdef UF_HIDDEN + { UF_HIDDEN, EXT_HIDDEN }, +#endif + + /* Do not remove. We need to guarantee that this array has at least one + * entry to build on HP-UX. + */ + { 0, 0 } + +}; + +static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf, + uint32 *smb_fflags, uint32 *smb_fmask) +{ +#ifdef HAVE_STAT_ST_FLAGS + int i; + + for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) { + *smb_fmask |= info2_flags_map[i].smb_fflag; + if (psbuf->st_flags & info2_flags_map[i].stat_fflag) { + *smb_fflags |= info2_flags_map[i].smb_fflag; + } + } +#endif /* HAVE_STAT_ST_FLAGS */ +} + +static BOOL map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf, + const uint32 smb_fflags, + const uint32 smb_fmask, + int *stat_fflags) +{ +#ifdef HAVE_STAT_ST_FLAGS + uint32 max_fmask = 0; + int i; + + *stat_fflags = psbuf->st_flags; + + /* For each flags requested in smb_fmask, check the state of the + * corresponding flag in smb_fflags and set or clear the matching + * stat flag. + */ + + for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) { + max_fmask |= info2_flags_map[i].smb_fflag; + if (smb_fmask & info2_flags_map[i].smb_fflag) { + if (smb_fflags & info2_flags_map[i].smb_fflag) { + *stat_fflags |= info2_flags_map[i].stat_fflag; + } else { + *stat_fflags &= ~info2_flags_map[i].stat_fflag; + } + } + } + + /* If smb_fmask is asking to set any bits that are not supported by + * our flag mappings, we should fail. + */ + if ((smb_fmask & max_fmask) != smb_fmask) { + return False; + } + + return True; +#else + return False; +#endif /* HAVE_STAT_ST_FLAGS */ +} + + +/* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition + * of file flags and birth (create) time. + */ +static char *store_file_unix_basic_info2(connection_struct *conn, + char *pdata, + files_struct *fsp, + const SMB_STRUCT_STAT *psbuf) +{ + uint32 file_flags = 0; + uint32 flags_mask = 0; + + pdata = store_file_unix_basic(conn, pdata, fsp, psbuf); + + /* Create (birth) time 64 bit */ + put_long_date_timespec(pdata, get_create_timespec(psbuf, False)); + pdata += 8; + + map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask); + SIVAL(pdata, 0, file_flags); /* flags */ + SIVAL(pdata, 4, flags_mask); /* mask */ + pdata += 8; + + return pdata; +} + /**************************************************************************** Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by file name or file id). @@ -2970,6 +3185,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { + return ERROR_NT(NT_STATUS_INVALID_LEVEL); + } + if(fsp && (fsp->fake_file_handle)) { /* * This is actually for the QUOTA_FAKE_FILE --metze @@ -3026,12 +3245,22 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { + return ERROR_NT(NT_STATUS_INVALID_LEVEL); + } + srvstr_get_path(inbuf, fname, ¶ms[6], sizeof(fname), total_params - 6, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, fname, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -3175,18 +3404,16 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd allocation_size = get_allocation_size(conn,fsp,&sbuf); if (fsp) { - if (fsp->pending_modtime) { + if (!null_timespec(fsp->pending_modtime)) { /* the pending modtime overrides the current modtime */ - mtime_ts.tv_sec = fsp->pending_modtime; - mtime_ts.tv_nsec = 0; + mtime_ts = fsp->pending_modtime; } } else { /* Do we have this path open ? */ files_struct *fsp1 = file_find_di_first(sbuf.st_dev, sbuf.st_ino); - if (fsp1 && fsp1->pending_modtime) { + if (fsp1 && !null_timespec(fsp1->pending_modtime)) { /* the pending modtime overrides the current modtime */ - mtime_ts.tv_sec = fsp1->pending_modtime; - mtime_ts.tv_nsec = 0; + mtime_ts = fsp1->pending_modtime; } if (fsp1 && fsp1->initial_allocation_size) { allocation_size = get_allocation_size(conn, fsp1, &sbuf); @@ -3539,6 +3766,22 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd break; + case SMB_QUERY_FILE_UNIX_INFO2: + + pdata = store_file_unix_basic_info2(conn, pdata, fsp, &sbuf); + data_size = PTR_DIFF(pdata,(*ppdata)); + + { + int i; + DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 ")); + + for (i=0; i<100; i++) + DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); + DEBUG(4,("\n")); + } + + break; + case SMB_QUERY_FILE_UNIX_LINK: { pstring buffer; @@ -3743,17 +3986,22 @@ NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring ne return status; } + status = check_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* source must already exist. */ if (!VALID_STAT(sbuf1)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - status = check_name(conn, oldname); + status = unix_convert(conn, newname, False, last_component_newname, &sbuf2); if (!NT_STATUS_IS_OK(status)) { - return NT_STATUS_ACCESS_DENIED; + return status; } - status = unix_convert(conn, newname, False, last_component_newname, &sbuf2); + status = check_name(conn, newname); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -3763,11 +4011,6 @@ NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring ne return NT_STATUS_OBJECT_NAME_COLLISION; } - status = check_name(conn, newname); - if (!NT_STATUS_IS_OK(status)) { - return NT_STATUS_ACCESS_DENIED; - } - /* No links from a directory. */ if (S_ISDIR(sbuf1.st_mode)) { return NT_STATUS_FILE_IS_A_DIRECTORY; @@ -3798,7 +4041,7 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, files_struct *fsp, const char *fname, const SMB_STRUCT_STAT *psbuf, - struct utimbuf tvs) + struct timespec ts[2]) { uint32 action = FILE_NOTIFY_CHANGE_LAST_ACCESS @@ -3810,26 +4053,30 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, } /* get some defaults (no modifications) if any info is zero or -1. */ - if (null_mtime(tvs.actime)) { - tvs.actime = psbuf->st_atime; + if (null_timespec(ts[0])) { + ts[0] = get_atimespec(psbuf); action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS; } - if (null_mtime(tvs.modtime)) { - tvs.modtime = psbuf->st_mtime; + if (null_timespec(ts[1])) { + ts[1] = get_mtimespec(psbuf); action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } - DEBUG(6,("smb_set_file_time: actime: %s " , ctime(&tvs.actime))); - DEBUG(6,("smb_set_file_time: modtime: %s ", ctime(&tvs.modtime))); + DEBUG(6,("smb_set_file_time: actime: %s " , time_to_asc(convert_timespec_to_time_t(ts[0])) )); + DEBUG(6,("smb_set_file_time: modtime: %s ", time_to_asc(convert_timespec_to_time_t(ts[1])) )); /* * Try and set the times of this file if * they are different from the current values. */ - if (psbuf->st_mtime == tvs.modtime && psbuf->st_atime == tvs.actime) { - return NT_STATUS_OK; + { + struct timespec mts = get_mtimespec(psbuf); + struct timespec ats = get_atimespec(psbuf); + if ((timespec_compare(&ts[0], &ats) == 0) && (timespec_compare(&ts[1], &mts) == 0)) { + return NT_STATUS_OK; + } } if(fsp != NULL) { @@ -3843,15 +4090,16 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, * away and will set it on file close and after a write. JRA. */ - if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) { - DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", ctime(&tvs.modtime) )); - fsp_set_pending_modtime(fsp, tvs.modtime); + if (!null_timespec(ts[1])) { + DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", + time_to_asc(convert_timespec_to_time_t(ts[1])) )); + fsp_set_pending_modtime(fsp, ts[1]); } } DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); - if(file_utime(conn, fname, &tvs)!=0) { + if(file_ntimes(conn, fname, ts)!=0) { return map_nt_error_from_unix(errno); } if (action != 0) { @@ -4030,6 +4278,12 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, delete_on_close = (CVAL(pdata,0) ? True : False); dosmode = dos_mode(conn, fname, psbuf); + DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, " + "delete_on_close = %u\n", + fsp->fsp_name, + (unsigned int)dosmode, + (unsigned int)delete_on_close )); + status = can_set_delete_on_close(fsp, delete_on_close, dosmode); if (!NT_STATUS_IS_OK(status)) { @@ -4132,7 +4386,6 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, pstring rel_name; char *last_dirp = NULL; - unix_format(link_target); if (*link_target == '/') { /* No absolute paths allowed. */ return NT_STATUS_ACCESS_DENIED; @@ -4186,7 +4439,10 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, return status; } - RESOLVE_DFSPATH_STATUS(oldname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n", fname, oldname)); @@ -4211,6 +4467,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, uint32 len; pstring newname; pstring base_name; + BOOL dest_has_wcard = False; NTSTATUS status = NT_STATUS_OK; char *p; @@ -4226,12 +4483,15 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status); + srvstr_get_path_wcard(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { return status; } - RESOLVE_DFSPATH_STATUS(newname, conn, inbuf, outbuf); + status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard); + if (!NT_STATUS_IS_OK(status)) { + return status; + } /* Check the new name has no '/' characters. */ if (strchr_m(newname, '/')) { @@ -4255,7 +4515,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, } else { DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n", fname, newname )); - status = rename_internals(conn, fname, base_name, 0, overwrite, False); + status = rename_internals(conn, fname, base_name, 0, overwrite, False, dest_has_wcard); } return status; @@ -4305,6 +4565,11 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } + DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n", + fname ? fname : fsp->fsp_name, + (unsigned int)num_file_acls, + (unsigned int)num_def_acls)); + if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls, pdata + SMB_POSIX_ACL_HEADER_SIZE)) { return map_nt_error_from_unix(errno); @@ -4386,6 +4651,14 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET); #endif /* HAVE_LONGLONG */ + DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u," + "lock_pid = %u, count = %.0f, offset = %.0f\n", + fsp->fsp_name, + (unsigned int)lock_type, + (unsigned int)lock_pid, + (double)count, + (double)offset )); + if (lock_type == UNLOCK_LOCK) { status = do_unlock(fsp, lock_pid, @@ -4439,22 +4712,25 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf) { - struct utimbuf tvs; + struct timespec ts[2]; if (total_data < 12) { return NT_STATUS_INVALID_PARAMETER; } /* access time */ - tvs.actime = srv_make_unix_date2(pdata+l1_fdateLastAccess); + ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastAccess)); /* write time */ - tvs.modtime = srv_make_unix_date2(pdata+l1_fdateLastWrite); + ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastWrite)); + + DEBUG(10,("smb_set_info_standard: file %s\n", + fname ? fname : fsp->fsp_name )); return smb_set_file_time(conn, fsp, fname, psbuf, - tvs); + ts); } /**************************************************************************** @@ -4469,10 +4745,10 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, SMB_STRUCT_STAT *psbuf) { /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */ - time_t write_time; - time_t changed_time; + struct timespec write_time; + struct timespec changed_time; uint32 dosmode = 0; - struct utimbuf tvs; + struct timespec ts[2]; NTSTATUS status = NT_STATUS_OK; if (total_data < 36) { @@ -4492,26 +4768,31 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, /* Ignore create time at offset pdata. */ /* access time */ - tvs.actime = convert_timespec_to_time_t(interpret_long_date(pdata+8)); + ts[0] = interpret_long_date(pdata+8); - write_time = convert_timespec_to_time_t(interpret_long_date(pdata+16)); - changed_time = convert_timespec_to_time_t(interpret_long_date(pdata+24)); + write_time = interpret_long_date(pdata+16); + changed_time = interpret_long_date(pdata+24); - tvs.modtime = MIN(write_time, changed_time); + /* mtime */ + ts[1] = timespec_min(&write_time, &changed_time); - if (write_time > tvs.modtime && write_time != (time_t)-1) { - tvs.modtime = write_time; + if ((timespec_compare(&write_time, &ts[1]) == 1) && !null_timespec(write_time)) { + ts[1] = write_time; } + /* Prefer a defined time to an undefined one. */ - if (null_mtime(tvs.modtime)) { - tvs.modtime = null_mtime(write_time) ? changed_time : write_time; + if (null_timespec(ts[1])) { + ts[1] = null_timespec(write_time) ? changed_time : write_time; } + DEBUG(10,("smb_set_file_basic_info: file %s\n", + fname ? fname : fsp->fsp_name )); + return smb_set_file_time(conn, fsp, fname, psbuf, - tvs); + ts); } /**************************************************************************** @@ -4725,7 +5006,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) { - struct utimbuf tvs; + struct timespec ts[2]; uint32 raw_unixmode; mode_t unixmode; SMB_OFF_T size = 0; @@ -4752,8 +5033,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, #endif /* LARGE_SMB_OFF_T */ } - tvs.actime = convert_timespec_to_time_t(interpret_long_date(pdata+24)); /* access_time */ - tvs.modtime = convert_timespec_to_time_t(interpret_long_date(pdata+32)); /* modification_time */ + ts[0] = interpret_long_date(pdata+24); /* access_time */ + ts[1] = interpret_long_date(pdata+32); /* modification_time */ set_owner = (uid_t)IVAL(pdata,40); set_grp = (gid_t)IVAL(pdata,48); raw_unixmode = IVAL(pdata,84); @@ -4796,8 +5077,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", /* Ensure we don't try and change anything else. */ raw_unixmode = SMB_MODE_NO_CHANGE; size = get_file_size(*psbuf); - tvs.modtime = psbuf->st_mtime; - tvs.actime = psbuf->st_atime; + ts[0] = get_atimespec(psbuf); + ts[1] = get_mtimespec(psbuf); /* * We continue here as we might want to change the * owner uid/gid. @@ -4876,7 +5157,68 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", fsp, fname, psbuf, - tvs); + ts); +} + +/**************************************************************************** + Deal with SMB_SET_FILE_UNIX_INFO2. +****************************************************************************/ + +static NTSTATUS smb_set_file_unix_info2(connection_struct *conn, + const char *pdata, + int total_data, + files_struct *fsp, + const char *fname, + SMB_STRUCT_STAT *psbuf) +{ + NTSTATUS status; + uint32 smb_fflags; + uint32 smb_fmask; + + if (total_data < 116) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* Start by setting all the fields that are common between UNIX_BASIC + * and UNIX_INFO2. + */ + status = smb_set_file_unix_basic(conn, pdata, total_data, + fsp, fname, psbuf); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + smb_fflags = IVAL(pdata, 108); + smb_fmask = IVAL(pdata, 112); + + /* NB: We should only attempt to alter the file flags if the client + * sends a non-zero mask. + */ + if (smb_fmask != 0) { + int stat_fflags = 0; + + if (!map_info2_flags_to_sbuf(psbuf, smb_fflags, smb_fmask, + &stat_fflags)) { + /* Client asked to alter a flag we don't understand. */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (fsp && fsp->fh->fd != -1) { + /* XXX: we should be using SMB_VFS_FCHFLAGS here. */ + return NT_STATUS_NOT_SUPPORTED; + } else { + if (SMB_VFS_CHFLAGS(conn, fname, stat_fflags) != 0) { + return map_nt_error_from_unix(errno); + } + } + } + + /* XXX: need to add support for changing the create_time here. You + * can do this for paths on Darwin with setattrlist(2). The right way + * to hook this up is probably by extending the VFS utimes interface. + */ + + return NT_STATUS_OK; } /**************************************************************************** @@ -4896,13 +5238,16 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, mode_t unixmode = (mode_t)0; files_struct *fsp = NULL; uint16 info_level_return = 0; + int info; char *pdata = *ppdata; - if (total_data < 10) { + if (total_data < 18) { return NT_STATUS_INVALID_PARAMETER; } raw_unixmode = IVAL(pdata,8); + /* Next 4 bytes are not yet defined. */ + status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_DIR, &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4910,6 +5255,9 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS; + DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n", + fname, (unsigned int)unixmode )); + status = open_directory(conn, fname, psbuf, @@ -4918,19 +5266,21 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, FILE_CREATE, 0, mod_unixmode, - NULL, + &info, &fsp); if (NT_STATUS_IS_OK(status)) { close_file(fsp, NORMAL_CLOSE); } - info_level_return = SVAL(pdata,12); + info_level_return = SVAL(pdata,16); if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) { - *pdata_return_size = 8 + SMB_FILE_UNIX_BASIC_SIZE; + *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE; + } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) { + *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE; } else { - *pdata_return_size = 8; + *pdata_return_size = 12; } /* Realloc the data size */ @@ -4941,15 +5291,21 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, } SSVAL(pdata,0,NO_OPLOCK_RETURN); - SSVAL(pdata,2,0); - - if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) { - SSVAL(pdata,4,SMB_QUERY_FILE_UNIX_BASIC); - SSVAL(pdata,6,0); /* Padding. */ - store_file_unix_basic(conn, pdata + 8, fsp, psbuf); - } else { - SSVAL(pdata,4,SMB_NO_INFO_LEVEL_RETURNED); - SSVAL(pdata,6,0); /* Padding. */ + SSVAL(pdata,2,0); /* No fnum. */ + SIVAL(pdata,4,info); /* Was directory created. */ + + switch (info_level_return) { + case SMB_QUERY_FILE_UNIX_BASIC: + SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC); + SSVAL(pdata,10,0); /* Padding. */ + store_file_unix_basic(conn, pdata + 12, fsp, psbuf); + case SMB_QUERY_FILE_UNIX_INFO2: + SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2); + SSVAL(pdata,10,0); /* Padding. */ + store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf); + default: + SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED); + SSVAL(pdata,10,0); /* Padding. */ } return status; @@ -4982,7 +5338,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, int info = 0; uint16 info_level_return = 0; - if (total_data < 14) { + if (total_data < 18) { return NT_STATUS_INVALID_PARAMETER; } @@ -5034,6 +5390,8 @@ static NTSTATUS smb_posix_open(connection_struct *conn, } raw_unixmode = IVAL(pdata,8); + /* Next 4 bytes are not yet defined. */ + status = unix_perms_from_wire(conn, psbuf, raw_unixmode, @@ -5056,6 +5414,11 @@ static NTSTATUS smb_posix_open(connection_struct *conn, mod_unixmode |= FILE_FLAG_NO_BUFFERING; } + DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n", + fname, + (unsigned int)wire_open_mode, + (unsigned int)unixmode )); + status = open_file_ntcreate(conn, fname, psbuf, @@ -5080,12 +5443,16 @@ static NTSTATUS smb_posix_open(connection_struct *conn, extended_oplock_granted = True; } - info_level_return = SVAL(pdata,12); + info_level_return = SVAL(pdata,16); + /* Allocate the correct return size. */ + if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) { - *pdata_return_size = 8 + SMB_FILE_UNIX_BASIC_SIZE; + *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE; + } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) { + *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE; } else { - *pdata_return_size = 8; + *pdata_return_size = 12; } /* Realloc the data size */ @@ -5109,13 +5476,20 @@ static NTSTATUS smb_posix_open(connection_struct *conn, } SSVAL(pdata,2,fsp->fnum); - if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) { - SSVAL(pdata,4,SMB_QUERY_FILE_UNIX_BASIC); - SSVAL(pdata,6,0); /* padding. */ - store_file_unix_basic(conn, pdata + 8, fsp, psbuf); - } else { - SSVAL(pdata,4,SMB_NO_INFO_LEVEL_RETURNED); - SSVAL(pdata,6,0); /* padding. */ + SIVAL(pdata,4,info); /* Was file created etc. */ + + switch (info_level_return) { + case SMB_QUERY_FILE_UNIX_BASIC: + SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC); + SSVAL(pdata,10,0); /* padding. */ + store_file_unix_basic(conn, pdata + 12, fsp, psbuf); + case SMB_QUERY_FILE_UNIX_INFO2: + SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2); + SSVAL(pdata,10,0); /* padding. */ + store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf); + default: + SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED); + SSVAL(pdata,10,0); /* padding. */ } return NT_STATUS_OK; } @@ -5132,12 +5506,28 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, { NTSTATUS status = NT_STATUS_OK; files_struct *fsp = NULL; + uint16 flags = 0; int info = 0; + if (total_data < 2) { + return NT_STATUS_INVALID_PARAMETER; + } + + flags = SVAL(pdata,0); + if (!VALID_STAT(*psbuf)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) && + !VALID_STAT_OF_DIR(*psbuf)) { + return NT_STATUS_NOT_A_DIRECTORY; + } + + DEBUG(10,("smb_posix_unlink: %s %s\n", + (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file", + fname)); + if (VALID_STAT_OF_DIR(*psbuf)) { status = open_directory(conn, fname, @@ -5150,17 +5540,34 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, &info, &fsp); } else { + char del = 1; + status = open_file_ntcreate(conn, fname, psbuf, DELETE_ACCESS, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, - FILE_DELETE_ON_CLOSE, + 0, FILE_FLAG_POSIX_SEMANTICS|0777, - INTERNAL_OPEN_ONLY, + 0, /* No oplock, but break existing ones. */ &info, &fsp); + /* + * For file opens we must set the delete on close + * after the open. + */ + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = smb_set_file_disposition_info(conn, + &del, + 1, + fsp, + fname, + psbuf); } if (!NT_STATUS_IS_OK(status)) { @@ -5251,13 +5658,24 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char return ERROR_NT(status); } - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); + } + return ERROR_NT(status); + } status = unix_convert(conn, fname, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); + } + /* * For CIFS UNIX extensions the target name may not exist. */ @@ -5266,12 +5684,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno))); return UNIXERROR(ERRDOS,ERRbadpath); } - - status = check_name(conn, fname); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - } if (!CAN_WRITE(conn)) { @@ -5294,9 +5706,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char SSVAL(params,0,0); - if (fsp && fsp->pending_modtime) { + if (fsp && !null_timespec(fsp->pending_modtime)) { /* the pending modtime overrides the current modtime */ - sbuf.st_mtime = fsp->pending_modtime; + set_mtimespec(&sbuf, fsp->pending_modtime); } switch (info_level) { @@ -5417,6 +5829,17 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char break; } + case SMB_SET_FILE_UNIX_INFO2: + { + status = smb_set_file_unix_info2(conn, + pdata, + total_data, + fsp, + fname, + &sbuf); + break; + } + case SMB_SET_FILE_UNIX_LINK: { if (tran_call != TRANSACT2_SETPATHINFO) { @@ -5576,6 +5999,12 @@ static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(status); } + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status))); + return ERROR_NT(status); + } + /* Any data in this call is an EA list. */ if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) { return ERROR_NT(NT_STATUS_EAS_NOT_SUPPORTED); @@ -5607,12 +6036,6 @@ static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } - status = check_name(conn, directory); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status))); - return ERROR_NT(status); - } - status = create_directory(conn, directory); if (!NT_STATUS_IS_OK(status)) { diff --git a/source/tdb/common/open.c b/source/tdb/common/open.c index 3f0c35331b2..c7fd3f66564 100644 --- a/source/tdb/common/open.c +++ b/source/tdb/common/open.c @@ -263,6 +263,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, tdb->map_size = st.st_size; tdb->device = st.st_dev; tdb->inode = st.st_ino; + tdb->max_dead_records = 0; tdb_mmap(tdb); if (locked) { if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) { @@ -321,6 +322,15 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, } } +/* + * Set the maximum number of dead records per hash chain + */ + +void tdb_set_max_dead(struct tdb_context *tdb, int max_dead) +{ + tdb->max_dead_records = max_dead; +} + /** * Close a database. * diff --git a/source/tdb/common/tdb.c b/source/tdb/common/tdb.c index bf4c01d1b3a..bf43701d2ed 100644 --- a/source/tdb/common/tdb.c +++ b/source/tdb/common/tdb.c @@ -258,6 +258,66 @@ int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct return 0; } +static int tdb_count_dead(struct tdb_context *tdb, u32 hash) +{ + int res = 0; + tdb_off_t rec_ptr; + struct list_struct rec; + + /* read in the hash top */ + if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) + return 0; + + while (rec_ptr) { + if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) + return 0; + + if (rec.magic == TDB_DEAD_MAGIC) { + res += 1; + } + rec_ptr = rec.next; + } + return res; +} + +/* + * Purge all DEAD records from a hash chain + */ +static int tdb_purge_dead(struct tdb_context *tdb, u32 hash) +{ + int res = -1; + struct list_struct rec; + tdb_off_t rec_ptr; + + if (tdb_lock(tdb, -1, F_WRLCK) == -1) { + return -1; + } + + /* read in the hash top */ + if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) + goto fail; + + while (rec_ptr) { + tdb_off_t next; + + if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) { + goto fail; + } + + next = rec.next; + + if (rec.magic == TDB_DEAD_MAGIC + && tdb_do_delete(tdb, rec_ptr, &rec) == -1) { + goto fail; + } + rec_ptr = next; + } + res = 0; + fail: + tdb_unlock(tdb, -1, F_WRLCK); + return res; +} + /* delete an entry in the database given a key */ static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash) { @@ -265,9 +325,42 @@ static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash) struct list_struct rec; int ret; - if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec))) - return -1; - ret = tdb_do_delete(tdb, rec_ptr, &rec); + if (tdb->max_dead_records != 0) { + + /* + * Allow for some dead records per hash chain, mainly for + * tdb's with a very high create/delete rate like locking.tdb. + */ + + if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) + return -1; + + if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) { + /* + * Don't let the per-chain freelist grow too large, + * delete all existing dead records + */ + tdb_purge_dead(tdb, hash); + } + + if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) { + tdb_unlock(tdb, BUCKET(hash), F_WRLCK); + return -1; + } + + /* + * Just mark the record as dead. + */ + rec.magic = TDB_DEAD_MAGIC; + ret = tdb_rec_write(tdb, rec_ptr, &rec); + } + else { + if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, + &rec))) + return -1; + + ret = tdb_do_delete(tdb, rec_ptr, &rec); + } if (ret == 0) { tdb_increment_seqnum(tdb); @@ -284,6 +377,35 @@ int tdb_delete(struct tdb_context *tdb, TDB_DATA key) return tdb_delete_hash(tdb, key, hash); } +/* + * See if we have a dead record around with enough space + */ +static tdb_off_t tdb_find_dead(struct tdb_context *tdb, u32 hash, + struct list_struct *r, tdb_len_t length) +{ + tdb_off_t rec_ptr; + + /* read in the hash top */ + if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) + return 0; + + /* keep looking until we find the right record */ + while (rec_ptr) { + if (tdb_rec_read(tdb, rec_ptr, r) == -1) + return 0; + + if (TDB_DEAD(r) && r->rec_len >= length) { + /* + * First fit for simple coding, TODO: change to best + * fit + */ + return rec_ptr; + } + rec_ptr = r->next; + } + return 0; +} + /* store an element in the database, replacing any existing element with the same key @@ -316,8 +438,7 @@ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) } else { /* first try in-place update, on modify or replace. */ if (tdb_update_hash(tdb, key, hash, dbuf) == 0) { - ret = 0; - goto fail; /* Well, not really failed */ + goto done; } if (tdb->ecode == TDB_ERR_NOEXIST && flag == TDB_MODIFY) { @@ -347,9 +468,56 @@ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) if (dbuf.dsize) memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize); + if (tdb->max_dead_records != 0) { + /* + * Allow for some dead records per hash chain, look if we can + * find one that can hold the new record. We need enough space + * for key, data and tailer. If we find one, we don't have to + * consult the central freelist. + */ + rec_ptr = tdb_find_dead( + tdb, hash, &rec, + key.dsize + dbuf.dsize + sizeof(tdb_off_t)); + + if (rec_ptr != 0) { + rec.key_len = key.dsize; + rec.data_len = dbuf.dsize; + rec.full_hash = hash; + rec.magic = TDB_MAGIC; + if (tdb_rec_write(tdb, rec_ptr, &rec) == -1 + || tdb->methods->tdb_write( + tdb, rec_ptr + sizeof(rec), + p, key.dsize + dbuf.dsize) == -1) { + goto fail; + } + goto done; + } + } + + /* + * We have to allocate some space from the freelist, so this means we + * have to lock it. Use the chance to purge all the DEAD records from + * the hash chain under the freelist lock. + */ + + if (tdb_lock(tdb, -1, F_WRLCK) == -1) { + goto fail; + } + + if ((tdb->max_dead_records != 0) + && (tdb_purge_dead(tdb, hash) == -1)) { + tdb_unlock(tdb, -1, F_WRLCK); + goto fail; + } + /* we have to allocate some space */ - if (!(rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec))) + rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec); + + tdb_unlock(tdb, -1, F_WRLCK); + + if (rec_ptr == 0) { goto fail; + } /* Read hash top into next ptr */ if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1) @@ -368,6 +536,7 @@ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) goto fail; } + done: ret = 0; fail: if (ret == 0) { diff --git a/source/tdb/common/tdb_private.h b/source/tdb/common/tdb_private.h index 7fc136c6a70..10bc6dacdcf 100644 --- a/source/tdb/common/tdb_private.h +++ b/source/tdb/common/tdb_private.h @@ -169,6 +169,7 @@ struct tdb_context { const struct tdb_methods *methods; struct tdb_transaction *transaction; int page_size; + int max_dead_records; }; diff --git a/source/tdb/include/tdb.h b/source/tdb/include/tdb.h index a0f6f983824..51bf709f442 100644 --- a/source/tdb/include/tdb.h +++ b/source/tdb/include/tdb.h @@ -94,6 +94,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode, const struct tdb_logging_context *log_ctx, tdb_hash_func hash_fn); +void tdb_set_max_dead(struct tdb_context *tdb, int max_dead); int tdb_reopen(struct tdb_context *tdb); int tdb_reopen_all(int parent_longlived); diff --git a/source/torture/cmd_vfs.c b/source/torture/cmd_vfs.c index 6cecd693f83..455ca1c82c7 100644 --- a/source/torture/cmd_vfs.c +++ b/source/torture/cmd_vfs.c @@ -783,14 +783,14 @@ static NTSTATUS cmd_getwd(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, static NTSTATUS cmd_utime(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv) { - struct utimbuf times; + struct timespec ts[2]; if (argc != 4) { printf("Usage: utime <path> <access> <modify>\n"); return NT_STATUS_OK; } - times.actime = atoi(argv[2]); - times.modtime = atoi(argv[3]); - if (SMB_VFS_UTIME(vfs->conn, argv[1], ×) != 0) { + ts[0] = convert_time_t_to_timespec(atoi(argv[2])); + ts[1] = convert_time_t_to_timespec(atoi(argv[3])); + if (SMB_VFS_NTIMES(vfs->conn, argv[1], ts) != 0) { printf("utime: error=%d (%s)\n", errno, strerror(errno)); return NT_STATUS_UNSUCCESSFUL; } diff --git a/source/torture/nsstest.c b/source/torture/nsstest.c index 4b894fbfc34..121679ed8cc 100644 --- a/source/torture/nsstest.c +++ b/source/torture/nsstest.c @@ -229,12 +229,15 @@ again: goto again; } if (status == NSS_STATUS_NOTFOUND) { + SAFE_FREE(buf); return NULL; } if (status != NSS_STATUS_SUCCESS) { report_nss_error("getgrnam", status); + SAFE_FREE(buf); return NULL; } + SAFE_FREE(buf); return &grp; } @@ -266,12 +269,15 @@ again: goto again; } if (status == NSS_STATUS_NOTFOUND) { + SAFE_FREE(buf); return NULL; } if (status != NSS_STATUS_SUCCESS) { report_nss_error("getgrgid", status); + SAFE_FREE(buf); return NULL; } + SAFE_FREE(buf); return &grp; } diff --git a/source/torture/torture.c b/source/torture/torture.c index 79444946122..5ab28438f21 100644 --- a/source/torture/torture.c +++ b/source/torture/torture.c @@ -4479,6 +4479,7 @@ static BOOL run_eatest(int dummy) printf("starting eatest\n"); if (!torture_open_connection(&cli, 0)) { + talloc_destroy(mem_ctx); return False; } @@ -4490,6 +4491,7 @@ static BOOL run_eatest(int dummy) if (fnum == -1) { printf("open failed - %s\n", cli_errstr(cli)); + talloc_destroy(mem_ctx); return False; } @@ -4500,6 +4502,7 @@ static BOOL run_eatest(int dummy) memset(ea_val, (char)i+1, i+1); if (!cli_set_ea_fnum(cli, fnum, ea_name, ea_val, i+1)) { printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli)); + talloc_destroy(mem_ctx); return False; } } @@ -4512,6 +4515,7 @@ static BOOL run_eatest(int dummy) memset(ea_val, (char)i+1, i+1); if (!cli_set_ea_path(cli, fname, ea_name, ea_val, i+1)) { printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli)); + talloc_destroy(mem_ctx); return False; } } @@ -4545,6 +4549,7 @@ static BOOL run_eatest(int dummy) slprintf(ea_name, sizeof(ea_name), "ea_%d", i); if (!cli_set_ea_path(cli, fname, ea_name, "", 0)) { printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli)); + talloc_destroy(mem_ctx); return False; } } diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c index 02a0b68932c..52af6e68d77 100644 --- a/source/utils/net_ads.c +++ b/source/utils/net_ads.c @@ -1118,6 +1118,72 @@ done: } /******************************************************************* + Set a machines dNSHostName and servicePrincipalName attributes + ********************************************************************/ + +static ADS_STATUS net_set_os_attributes(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, + const char *os_name, const char *os_version ) +{ + ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN); + char *new_dn; + ADS_MODLIST mods; + LDAPMessage *res = NULL; + char *dn_string = NULL; + const char *machine_name = global_myname(); + int count; + char *os_sp = NULL; + + if ( !os_name || !os_version ) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + /* Find our DN */ + + status = ads_find_machine_acct(ads_s, &res, machine_name); + if (!ADS_ERR_OK(status)) + return status; + + if ( (count = ads_count_replies(ads_s, res)) != 1 ) { + DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count)); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) { + DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n")); + goto done; + } + + new_dn = talloc_strdup(ctx, dn_string); + ads_memfree(ads_s, dn_string); + if (!new_dn) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + /* now do the mods */ + + if (!(mods = ads_init_mods(ctx))) { + goto done; + } + + os_sp = talloc_asprintf( ctx, "Samba %s", SAMBA_VERSION_STRING ); + + /* fields of primary importance */ + + ads_mod_str(ctx, &mods, "operatingSystem", os_name); + ads_mod_str(ctx, &mods, "operatingSystemVersion", os_version); + if ( os_sp ) + ads_mod_str(ctx, &mods, "operatingSystemServicePack", os_sp); + + status = ads_gen_mod(ads_s, new_dn, mods); + +done: + ads_msgfree(ads_s, res); + TALLOC_FREE( os_sp ); + + return status; +} + +/******************************************************************* join a domain using ADS (LDAP mods) ********************************************************************/ @@ -1386,6 +1452,8 @@ int net_ads_join(int argc, const char **argv) int i; fstring dc_name; struct in_addr dcip; + const char *os_name = NULL; + const char *os_version = NULL; nt_status = check_ads_config(); if (!NT_STATUS_IS_OK(nt_status)) { @@ -1427,7 +1495,21 @@ int net_ads_join(int argc, const char **argv) } else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) { if ( (create_in_ou = get_string_param(argv[i])) == NULL ) { - d_fprintf(stderr, "Please supply a valid OU path\n"); + d_fprintf(stderr, "Please supply a valid OU path.\n"); + nt_status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + } + else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) { + if ( (os_name = get_string_param(argv[i])) == NULL ) { + d_fprintf(stderr, "Please supply a operating system name.\n"); + nt_status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + } + else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) { + if ( (os_version = get_string_param(argv[i])) == NULL ) { + d_fprintf(stderr, "Please supply a valid operating system version.\n"); nt_status = NT_STATUS_INVALID_PARAMETER; goto fail; } @@ -1546,7 +1628,18 @@ int net_ads_join(int argc, const char **argv) } } + /* Try to set the operatingSystem attributes if asked */ + + if ( os_name && os_version ) { + status = net_set_os_attributes( ctx, ads, os_name, os_version ); + if ( !ADS_ERR_OK(status) ) { + d_fprintf(stderr, "Failed to set operatingSystem attributes. " + "Are you a Domain Admin?\n"); + } + } + /* Now build the keytab, using the same ADS connection */ + if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) { DEBUG(1,("Error creating host keytab!\n")); } @@ -1819,13 +1912,16 @@ static int net_ads_printer_publish(int argc, const char **argv) TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish"); ADS_MODLIST mods = ads_init_mods(mem_ctx); char *prt_dn, *srv_dn, **srv_cn; + char *srv_cn_escaped = NULL, *printername_escaped = NULL; LDAPMessage *res = NULL; if (!ADS_ERR_OK(ads_startup(True, &ads))) { + talloc_destroy(mem_ctx); return -1; } if (argc < 1) { + talloc_destroy(mem_ctx); return net_ads_printer_usage(argc, argv); } @@ -1853,6 +1949,7 @@ static int net_ads_printer_publish(int argc, const char **argv) d_fprintf(stderr, "Unable to open a connnection to %s to obtain data " "for %s\n", servername, printername); ads_destroy(&ads); + talloc_destroy(mem_ctx); return -1; } @@ -1864,37 +1961,60 @@ static int net_ads_printer_publish(int argc, const char **argv) d_fprintf(stderr, "Could not find machine account for server %s\n", servername); ads_destroy(&ads); + talloc_destroy(mem_ctx); return -1; } srv_dn = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res); srv_cn = ldap_explode_dn(srv_dn, 1); - asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn); + srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]); + printername_escaped = escape_rdn_val_string_alloc(printername); + if (!srv_cn_escaped || !printername_escaped) { + SAFE_FREE(srv_cn_escaped); + SAFE_FREE(printername_escaped); + d_fprintf(stderr, "Internal error, out of memory!"); + ads_destroy(&ads); + talloc_destroy(mem_ctx); + return -1; + } + + asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn); + + SAFE_FREE(srv_cn_escaped); + SAFE_FREE(printername_escaped); pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status); if (!pipe_hnd) { d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n", servername); + SAFE_FREE(prt_dn); ads_destroy(&ads); + talloc_destroy(mem_ctx); return -1; } if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods, printername))) { + SAFE_FREE(prt_dn); ads_destroy(&ads); + talloc_destroy(mem_ctx); return -1; } rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods); if (!ADS_ERR_OK(rc)) { d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc)); + SAFE_FREE(prt_dn); ads_destroy(&ads); + talloc_destroy(mem_ctx); return -1; } d_printf("published printer\n"); + SAFE_FREE(prt_dn); ads_destroy(&ads); + talloc_destroy(mem_ctx); return 0; } @@ -2158,6 +2278,7 @@ static int net_ads_dn_usage(int argc, const char **argv) "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\ "to show in the results\n\n"\ "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n" + "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n" ); net_common_flags_usage(argc, argv); return -1; diff --git a/source/utils/net_ads_gpo.c b/source/utils/net_ads_gpo.c index 1865aee3d41..83cc2fe8fcf 100644 --- a/source/utils/net_ads_gpo.c +++ b/source/utils/net_ads_gpo.c @@ -351,6 +351,7 @@ static int net_ads_gpo_add_link(int argc, const char **argv) if (argc < 2) { printf("usage: net ads gpo addlink <linkdn> <gpodn> [options]\n"); + printf("note: DNs must be provided properly escaped.\n See RFC 4514 for details\n"); return -1; } diff --git a/source/utils/net_rpc.c b/source/utils/net_rpc.c index 34e87ddbd21..56aee3be91a 100644 --- a/source/utils/net_rpc.c +++ b/source/utils/net_rpc.c @@ -3585,15 +3585,23 @@ static void copy_fn(const char *mnt, file_info *f, const char *mask, void *state **/ BOOL sync_files(struct copy_clistate *cp_clistate, pstring mask) { + struct cli_state *targetcli; + pstring targetpath; DEBUG(3,("calling cli_list with mask: %s\n", mask)); - if (cli_list(cp_clistate->cli_share_src, mask, cp_clistate->attribute, copy_fn, cp_clistate) == -1) { - d_fprintf(stderr, "listing %s failed with error: %s\n", + if ( !cli_resolve_path( "", cp_clistate->cli_share_src, mask, &targetcli, targetpath ) ) { + d_fprintf(stderr, "cli_resolve_path %s failed with error: %s\n", mask, cli_errstr(cp_clistate->cli_share_src)); return False; } + if (cli_list(targetcli, targetpath, cp_clistate->attribute, copy_fn, cp_clistate) == -1) { + d_fprintf(stderr, "listing %s failed with error: %s\n", + mask, cli_errstr(targetcli)); + return False; + } + return True; } @@ -4934,12 +4942,12 @@ static int rpc_file_close(int argc, const char **argv) * @param str3 strings for FILE_INFO_3 **/ -static void display_file_info_3(FILE_INFO_3 *info3, FILE_INFO_3_STR *str3) +static void display_file_info_3( FILE_INFO_3 *info3 ) { fstring user = "", path = ""; - rpcstr_pull_unistr2_fstring(user, &str3->uni_user_name); - rpcstr_pull_unistr2_fstring(path, &str3->uni_path_name); + rpcstr_pull_unistr2_fstring(user, info3->user); + rpcstr_pull_unistr2_fstring(path, info3->path); d_printf("%-7.1d %-20.20s 0x%-4.2x %-6.1d %s\n", info3->id, user, info3->perms, info3->num_locks, path); @@ -4994,8 +5002,7 @@ static NTSTATUS rpc_file_list_internals(const DOM_SID *domain_sid, "\nFileId Opened by Perms Locks Path"\ "\n------ --------- ----- ----- ---- \n"); for (i = 0; i < ctr.num_entries; i++) - display_file_info_3(&ctr.file.info3[i].info_3, - &ctr.file.info3[i].info_3_str); + display_file_info_3(&ctr.file.info3[i]); done: return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; } @@ -6072,6 +6079,7 @@ static int rpc_trustdom_list(int argc, const char **argv) if (!pipe_hnd) { DEBUG(0, ("Could not initialise lsa pipe. Error was %s\n", nt_errstr(nt_status) )); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; }; @@ -6081,6 +6089,7 @@ static int rpc_trustdom_list(int argc, const char **argv) if (NT_STATUS_IS_ERR(nt_status)) { DEBUG(0, ("Couldn't open policy handle. Error was %s\n", nt_errstr(nt_status))); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; }; @@ -6093,6 +6102,7 @@ static int rpc_trustdom_list(int argc, const char **argv) if (NT_STATUS_IS_ERR(nt_status)) { DEBUG(0, ("LSA Query Info failed. Returned error was %s\n", nt_errstr(nt_status))); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; } @@ -6112,6 +6122,7 @@ static int rpc_trustdom_list(int argc, const char **argv) if (NT_STATUS_IS_ERR(nt_status)) { DEBUG(0, ("Couldn't enumerate trusted domains. Error was %s\n", nt_errstr(nt_status))); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; }; @@ -6133,6 +6144,7 @@ static int rpc_trustdom_list(int argc, const char **argv) if (NT_STATUS_IS_ERR(nt_status)) { DEBUG(0, ("Couldn't properly close lsa policy handle. Error was %s\n", nt_errstr(nt_status))); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; }; @@ -6151,6 +6163,7 @@ static int rpc_trustdom_list(int argc, const char **argv) pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &nt_status); if (!pipe_hnd) { DEBUG(0, ("Could not initialise samr pipe. Error was %s\n", nt_errstr(nt_status))); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; }; @@ -6161,6 +6174,7 @@ static int rpc_trustdom_list(int argc, const char **argv) if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("Couldn't open SAMR policy handle. Error was %s\n", nt_errstr(nt_status))); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; }; @@ -6173,6 +6187,7 @@ static int rpc_trustdom_list(int argc, const char **argv) if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("Couldn't open domain object. Error was %s\n", nt_errstr(nt_status))); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; }; @@ -6191,6 +6206,7 @@ static int rpc_trustdom_list(int argc, const char **argv) if (NT_STATUS_IS_ERR(nt_status)) { DEBUG(0, ("Couldn't enumerate accounts. Error was: %s\n", nt_errstr(nt_status))); + cli_shutdown(cli); talloc_destroy(mem_ctx); return -1; }; diff --git a/source/utils/net_sam.c b/source/utils/net_sam.c index 8800cb36060..bf397803bc5 100644 --- a/source/utils/net_sam.c +++ b/source/utils/net_sam.c @@ -1043,6 +1043,7 @@ static int net_sam_provision(int argc, const char **argv) d_fprintf(stderr, "Failed to add Domain Users group to ldap directory\n"); } } else { + domusers_gid = gmap.gid; d_printf("found!\n"); } @@ -1096,6 +1097,7 @@ domu_done: d_fprintf(stderr, "Failed to add Domain Admins group to ldap directory\n"); } } else { + domadmins_gid = gmap.gid; d_printf("found!\n"); } @@ -1124,7 +1126,7 @@ doma_done: d_printf("Adding the Administrator user.\n"); if (domadmins_gid == -1) { - d_fprintf(stderr, "Can't create Administrtor user, Domain Admins group not available!\n"); + d_fprintf(stderr, "Can't create Administrator user, Domain Admins group not available!\n"); goto done; } if (!winbind_allocate_uid(&uid)) { @@ -1238,8 +1240,12 @@ doma_done: smbldap_set_mod(&mods, LDAP_MOD_ADD, "displayName", pwd->pw_name); smbldap_set_mod(&mods, LDAP_MOD_ADD, "uidNumber", uidstr); smbldap_set_mod(&mods, LDAP_MOD_ADD, "gidNumber", gidstr); - smbldap_set_mod(&mods, LDAP_MOD_ADD, "homeDirectory", pwd->pw_dir); - smbldap_set_mod(&mods, LDAP_MOD_ADD, "loginShell", pwd->pw_shell); + if ((pwd->pw_dir != NULL) && (pwd->pw_dir[0] != '\0')) { + smbldap_set_mod(&mods, LDAP_MOD_ADD, "homeDirectory", pwd->pw_dir); + } + if ((pwd->pw_shell != NULL) && (pwd->pw_shell[0] != '\0')) { + smbldap_set_mod(&mods, LDAP_MOD_ADD, "loginShell", pwd->pw_shell); + } smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaSID", sid_string_static(&sid)); smbldap_set_mod(&mods, LDAP_MOD_ADD, "sambaAcctFlags", pdb_encode_acct_ctrl(ACB_NORMAL|ACB_DISABLED, @@ -1261,7 +1267,7 @@ doma_done: pwd = getpwnam_alloc(NULL, lp_guestaccount()); if (!pwd) { d_fprintf(stderr, "Failed to find just created Guest account!\n" - " Is nssswitch properly configured?!\n"); + " Is nss properly configured?!\n"); goto failed; } diff --git a/source/utils/net_status.c b/source/utils/net_status.c index c68c9f6e2fb..bfc30eac78a 100644 --- a/source/utils/net_status.c +++ b/source/utils/net_status.c @@ -104,7 +104,7 @@ static int show_share(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, d_printf("%-10.10s %s %-12s %s", crec.name,procid_str_static(&crec.pid), crec.machine, - time_to_asc(&crec.start)); + time_to_asc(crec.start)); return 0; } @@ -173,7 +173,7 @@ static int show_share_parseable(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, guest ? "" : gidtoname(ids->entries[i].gid), crec.machine, guest ? "" : ids->entries[i].hostname, - time_to_asc(&crec.start)); + time_to_asc(crec.start)); return 0; } diff --git a/source/utils/ntlm_auth.c b/source/utils/ntlm_auth.c index 1e7b361e860..1f0a915574d 100644 --- a/source/utils/ntlm_auth.c +++ b/source/utils/ntlm_auth.c @@ -2303,7 +2303,8 @@ enum { } } - if (opt_domain == NULL || !*opt_domain) { + /* Note: if opt_domain is "" then send no domain */ + if (opt_domain == NULL) { opt_domain = get_winbind_domain(); } diff --git a/source/utils/pdbedit.c b/source/utils/pdbedit.c index d79ab187a3b..d1a87260fa9 100644 --- a/source/utils/pdbedit.c +++ b/source/utils/pdbedit.c @@ -573,6 +573,7 @@ static int new_user (struct pdb_methods *in, const char *username, if (sscanf(user_sid, "%d", &u_rid) != 1) { fprintf(stderr, "Error passed string is not a complete user SID or RID!\n"); + TALLOC_FREE(sam_pwent); return -1; } sid_copy(&u_sid, get_global_sam_sid()); diff --git a/source/utils/smbcontrol.c b/source/utils/smbcontrol.c index ec1e101e061..060079a5735 100644 --- a/source/utils/smbcontrol.c +++ b/source/utils/smbcontrol.c @@ -1145,22 +1145,12 @@ int main(int argc, const char **argv) poptContext pc; int opt; - static struct poptOption wbinfo_options[] = { + static struct poptOption long_options[] = { + POPT_AUTOHELP { "timeout", 't', POPT_ARG_INT, &timeout, 't', "Set timeout value in seconds", "TIMEOUT" }, - { "configfile", 's', POPT_ARG_STRING, NULL, 's', - "Use alternative configuration file", "CONFIGFILE" }, - - POPT_TABLEEND - }; - - struct poptOption options[] = { - { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, - "Options" }, - - POPT_AUTOHELP - POPT_COMMON_VERSION + POPT_COMMON_SAMBA POPT_TABLEEND }; @@ -1171,7 +1161,7 @@ int main(int argc, const char **argv) /* Parse command line arguments using popt */ pc = poptGetContext( - "smbcontrol", argc, (const char **)argv, options, 0); + "smbcontrol", argc, (const char **)argv, long_options, 0); poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> " "<parameters>"); @@ -1182,11 +1172,6 @@ int main(int argc, const char **argv) while ((opt = poptGetNextOpt(pc)) != -1) { switch(opt) { case 't': /* --timeout */ - argc -= 2; - break; - case 's': /* --configfile */ - pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc)); - argc -= 2; break; default: fprintf(stderr, "Invalid option\n"); @@ -1200,7 +1185,10 @@ int main(int argc, const char **argv) correct value in the above switch statement. */ argv = (const char **)poptGetArgs(pc); - argc--; /* Don't forget about argv[0] */ + argc = 0; + while (argv[argc] != NULL) { + argc++; + } if (argc == 1) usage(&pc); diff --git a/source/utils/status.c b/source/utils/status.c index 4f66501511b..deba6a9523b 100644 --- a/source/utils/status.c +++ b/source/utils/status.c @@ -162,7 +162,7 @@ static void print_share_mode(const struct share_mode_entry *e, d_printf("NONE "); } - d_printf(" %s %s %s",sharepath, fname, time_to_asc((time_t *)&e->time.tv_sec)); + d_printf(" %s %s %s",sharepath, fname, time_to_asc((time_t)e->time.tv_sec)); } } @@ -207,7 +207,7 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st d_printf("%-10s %s %-12s %s", crec.name,procid_str_static(&crec.pid), crec.machine, - time_to_asc(&crec.start)); + time_to_asc(crec.start)); return 0; } diff --git a/source/utils/status_profile.c b/source/utils/status_profile.c index 9224fc176cb..b4c4940f3fd 100644 --- a/source/utils/status_profile.c +++ b/source/utils/status_profile.c @@ -113,8 +113,8 @@ BOOL status_profile_dump(BOOL verbose) d_printf("chdir_time: %u\n", profile_p->syscall_chdir_time); d_printf("getwd_count: %u\n", profile_p->syscall_getwd_count); d_printf("getwd_time: %u\n", profile_p->syscall_getwd_time); - d_printf("utime_count: %u\n", profile_p->syscall_utime_count); - d_printf("utime_time: %u\n", profile_p->syscall_utime_time); + d_printf("ntimes_count: %u\n", profile_p->syscall_ntimes_count); + d_printf("ntimes_time: %u\n", profile_p->syscall_ntimes_time); d_printf("ftruncate_count: %u\n", profile_p->syscall_ftruncate_count); d_printf("ftruncate_time: %u\n", profile_p->syscall_ftruncate_time); d_printf("fcntl_lock_count: %u\n", profile_p->syscall_fcntl_lock_count); diff --git a/source/web/statuspage.c b/source/web/statuspage.c index 459b679d817..a88e5debd0e 100644 --- a/source/web/statuspage.c +++ b/source/web/statuspage.c @@ -101,7 +101,7 @@ static char *mapPid2Machine (struct process_id pid) static char *tstring(time_t t) { static pstring buf; - pstrcpy(buf, time_to_asc(&t)); + pstrcpy(buf, time_to_asc(t)); all_string_sub(buf," "," ",sizeof(buf)); return buf; } |