From 127e77e6e334fdc33086bffcbe00d340c0ba0097 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 17 Aug 2002 15:27:10 +0000 Subject: Sync 3.0 branch with head (This used to be commit 42615b945e2e48e53a21ea47f2e45407913a6a1e) --- source3/smbd/blocking.c | 23 +- source3/smbd/chgpasswd.c | 8 +- source3/smbd/conn.c | 23 +- source3/smbd/connection.c | 8 +- source3/smbd/dir.c | 69 ++++ source3/smbd/dosmode.c | 92 ++--- source3/smbd/fileio.c | 2 +- source3/smbd/filename.c | 1 - source3/smbd/lanman.c | 41 +- source3/smbd/mangle_hash2.c | 6 +- source3/smbd/negprot.c | 21 +- source3/smbd/nttrans.c | 960 +++++++++++++++++++++++--------------------- source3/smbd/password.c | 36 +- source3/smbd/posix_acls.c | 2 +- source3/smbd/process.c | 21 +- source3/smbd/reply.c | 53 ++- source3/smbd/server.c | 157 +++++--- source3/smbd/service.c | 36 +- source3/smbd/session.c | 74 ++-- source3/smbd/sesssetup.c | 119 +++--- source3/smbd/trans2.c | 88 ++-- source3/smbd/uid.c | 86 ++-- source3/smbd/vfs.c | 147 +++++-- 23 files changed, 1188 insertions(+), 885 deletions(-) (limited to 'source3') diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index d4a53d9a6d..6623c6df64 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -282,9 +282,10 @@ static BOOL process_lockread(blocking_lock_record *blr) status = do_lock_spin( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, READ_LOCK); if (NT_STATUS_V(status)) { - if ((errno != EACCES) && (errno != EAGAIN)) { + if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && + !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { /* - * We have other than a "can't get lock" POSIX + * We have other than a "can't get lock" * error. Send an error. * Return True so we get dequeued. */ @@ -348,9 +349,10 @@ static BOOL process_lock(blocking_lock_record *blr) status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)count, (SMB_BIG_UINT)offset, WRITE_LOCK); if (NT_STATUS_IS_ERR(status)) { - if((errno != EACCES) && (errno != EAGAIN)) { + if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && + !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { /* - * We have other than a "can't get lock" POSIX + * We have other than a "can't get lock" * error. Send an error. * Return True so we get dequeued. */ @@ -432,12 +434,13 @@ static BOOL process_lockingX(blocking_lock_record *blr) reply_lockingX_success(blr); return True; - } else if ((errno != EACCES) && (errno != EAGAIN)) { - /* - * We have other than a "can't get lock" POSIX - * error. Free any locks we had and return an error. - * Return True so we get dequeued. - */ + } else if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && + !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { + /* + * We have other than a "can't get lock" + * error. Free any locks we had and return an error. + * Return True so we get dequeued. + */ blocking_lock_reply_error(blr, status); return True; diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index 68871deb90..9e593b022e 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -167,17 +167,17 @@ static int dochild(int master, const char *slavedev, const struct passwd *pass, /* Make slave stdin/out/err of child. */ - if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) + if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO) { DEBUG(3, ("Could not re-direct stdin\n")); return (False); } - if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) + if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) { DEBUG(3, ("Could not re-direct stdout\n")); return (False); } - if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) + if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO) { DEBUG(3, ("Could not re-direct stderr\n")); return (False); @@ -196,7 +196,9 @@ static int dochild(int master, const char *slavedev, const struct passwd *pass, } stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); stermios.c_lflag |= ICANON; +#ifdef ONLCR stermios.c_oflag &= ~(ONLCR); +#endif if (tcsetattr(0, TCSANOW, &stermios) < 0) { DEBUG(3, ("could not set attributes of pty\n")); diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c index c0aa447016..d70e50f899 100644 --- a/source3/smbd/conn.c +++ b/source3/smbd/conn.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. Manage connections_struct structures Copyright (C) Andrew Tridgell 1998 + Copyright (C) Alexander Bokovoy 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -162,11 +163,25 @@ BOOL conn_idle_all(time_t t, int deadtime) void conn_free(connection_struct *conn) { + smb_vfs_handle_struct *handle, *thandle; + void (*done_fptr)(connection_struct *the_conn); + /* Free vfs_connection_struct */ - - if (conn->dl_handle != NULL) { - /* Close dlopen() handle */ - sys_dlclose(conn->dl_handle); + handle = conn->vfs_private; + while(handle) { + /* Close dlopen() handle */ + done_fptr = (void (*)(connection_struct *))sys_dlsym(handle->handle, "vfs_done"); + + if (done_fptr == NULL) { + DEBUG(3, ("No vfs_done() symbol found in module with handle %p, ignoring\n", handle->handle)); + } else { + done_fptr(conn); + } + sys_dlclose(handle->handle); + DLIST_REMOVE(conn->vfs_private, handle); + thandle = handle->next; + SAFE_FREE(handle); + handle = thandle; } DLIST_REMOVE(Connections, conn); diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c index c9815dbf8c..5609c2963d 100644 --- a/source3/smbd/connection.c +++ b/source3/smbd/connection.c @@ -20,7 +20,6 @@ #include "includes.h" -extern fstring remote_machine; static TDB_CONTEXT *tdb; /**************************************************************************** @@ -29,6 +28,11 @@ static TDB_CONTEXT *tdb; TDB_CONTEXT *conn_tdb_ctx(void) { + if (!tdb) { + tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, + O_RDWR | O_CREAT, 0644); + } + return tdb; } @@ -173,7 +177,7 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO } crec.start = time(NULL); - StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1); + StrnCpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)-1); StrnCpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1); dbuf.dptr = (char *)&crec; diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 7dd425ef8a..1a18476b75 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -721,6 +721,62 @@ static BOOL user_can_read_file(connection_struct *conn, char *name) &access_granted, &status); } +/******************************************************************* +check to see if a user can write a file (and only files, we do not +check dirs on this one). This is only approximate, +it is used as part of the "hide unwriteable" option. Don't +use it for anything security sensitive +********************************************************************/ + +static BOOL user_can_write_file(connection_struct *conn, char *name) +{ + extern struct current_user current_user; + SMB_STRUCT_STAT ste; + SEC_DESC *psd = NULL; + size_t sd_size; + files_struct *fsp; + int smb_action; + int access_mode; + NTSTATUS status; + uint32 access_granted; + + ZERO_STRUCT(ste); + + /* + * If user is a member of the Admin group + * we never hide files from them. + */ + + if (conn->admin_user) + return True; + + /* If we can't stat it does not show it */ + if (vfs_stat(conn, name, &ste) != 0) + return False; + + /* Pseudo-open the file (note - no fd's created). */ + + if(S_ISDIR(ste.st_mode)) + return True; + else + fsp = open_file_shared1(conn, name, &ste, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action); + + if (!fsp) + return False; + + /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ + sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); + close_file(fsp, False); + + /* No access if SD get failed. */ + if (!sd_size) + return False; + + return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA, + &access_granted, &status); +} + /******************************************************************* Open a directory. ********************************************************************/ @@ -781,6 +837,19 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto) continue; } + /* Honour _hide unwriteable_ option */ + if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) { + char *entry; + int ret=0; + + if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { + ret = user_can_write_file(conn, entry); + SAFE_FREE(entry); + } + if (!ret) + continue; + } + if (used + l > dirp->mallocsize) { int s = MAX(used+l,used+2000); char *r; diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index dcffe3aa90..77d8c9cc92 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -115,65 +115,67 @@ mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname) /**************************************************************************** change a unix mode to a dos mode ****************************************************************************/ -int dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf) +uint32 dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf) { - int result = 0; + int result = 0; - DEBUG(8,("dos_mode: %s\n", path)); + DEBUG(8,("dos_mode: %s\n", path)); - if ((sbuf->st_mode & S_IWUSR) == 0) - result |= aRONLY; + if ((sbuf->st_mode & S_IWUSR) == 0) + result |= aRONLY; + + if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0)) + result |= aARCH; - if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0)) - result |= aARCH; - - if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0)) - result |= aSYSTEM; - - if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0)) - result |= aHIDDEN; + if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0)) + result |= aSYSTEM; + + if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0)) + result |= aHIDDEN; - if (S_ISDIR(sbuf->st_mode)) - result = aDIR | (result & aRONLY); + if (S_ISDIR(sbuf->st_mode)) + result = aDIR | (result & aRONLY); + + if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)sbuf->st_blksize) { + result |= FILE_ATTRIBUTE_SPARSE; + } #ifdef S_ISLNK #if LINKS_READ_ONLY - if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode)) - result |= aRONLY; + if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode)) + result |= aRONLY; #endif #endif - /* hide files with a name starting with a . */ - if (lp_hide_dot_files(SNUM(conn))) - { - char *p = strrchr_m(path,'/'); - if (p) - p++; - else - p = path; - - if (p[0] == '.' && p[1] != '.' && p[1] != 0) - result |= aHIDDEN; - } - - /* Optimization : Only call is_hidden_path if it's not already - hidden. */ - if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) - { - result |= aHIDDEN; - } - - DEBUG(8,("dos_mode returning ")); + /* hide files with a name starting with a . */ + if (lp_hide_dot_files(SNUM(conn))) { + char *p = strrchr_m(path,'/'); + if (p) + p++; + else + p = path; + + if (p[0] == '.' && p[1] != '.' && p[1] != 0) + result |= aHIDDEN; + } + + /* Optimization : Only call is_hidden_path if it's not already + hidden. */ + if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) { + result |= aHIDDEN; + } - if (result & aHIDDEN) DEBUG(8, ("h")); - if (result & aRONLY ) DEBUG(8, ("r")); - if (result & aSYSTEM) DEBUG(8, ("s")); - if (result & aDIR ) DEBUG(8, ("d")); - if (result & aARCH ) DEBUG(8, ("a")); + DEBUG(8,("dos_mode returning ")); - DEBUG(8,("\n")); + if (result & aHIDDEN) DEBUG(8, ("h")); + if (result & aRONLY ) DEBUG(8, ("r")); + if (result & aSYSTEM) DEBUG(8, ("s")); + if (result & aDIR ) DEBUG(8, ("d")); + if (result & aARCH ) DEBUG(8, ("a")); + + DEBUG(8,("\n")); - return(result); + return(result); } /******************************************************************* diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index 710ba396d8..89f05092b4 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -163,7 +163,7 @@ ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n) int write_path = -1; if (fsp->print_file) - return print_job_write(fsp->print_jobid, data, n); + return print_job_write(SNUM(fsp->conn), fsp->print_jobid, data, n); if (!fsp->can_write) { errno = EPERM; diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index e5f9b7a0ae..ce98af4ace 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -29,7 +29,6 @@ extern BOOL case_sensitive; extern BOOL case_preserve; extern BOOL short_case_preserve; -extern fstring remote_machine; extern BOOL use_mangled_map; static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache); diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index 996a17e932..8bfad4ab33 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -443,7 +443,7 @@ static void fill_printjob_info(connection_struct *conn, int snum, int uLevel, /* the client expects localtime */ t -= TimeDiff(t); - PACKI(desc,"W",queue->job); /* uJobId */ + PACKI(desc,"W",pjobid_to_rap(snum,queue->job)); /* uJobId */ if (uLevel == 1) { PACKS(desc,"B21",queue->fs_user); /* szUserName */ PACKS(desc,"B",""); /* pad */ @@ -933,7 +933,7 @@ static BOOL api_DosPrintQGetInfo(connection_struct *conn, if (!mdrcnt && lp_disable_spoolss()) desc.errcode = ERRbuftoosmall; - *rdata_len = desc.usedlen; + *rdata_len = desc.usedlen; *rparam_len = 6; *rparam = REALLOC(*rparam,*rparam_len); SSVALS(*rparam,0,desc.errcode); @@ -2181,11 +2181,14 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param char *str1 = param+2; char *str2 = skip_string(str1,1); char *p = skip_string(str2,1); - int jobid, errcode; + uint32 jobid; + int snum; + int errcode; extern struct current_user current_user; WERROR werr = WERR_OK; - jobid = SVAL(p,0); + if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) + return False; /* check it's a supported varient */ if (!(strcsequal(str1,"W") && strcsequal(str2,""))) @@ -2195,7 +2198,7 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param *rparam = REALLOC(*rparam,*rparam_len); *rdata_len = 0; - if (!print_job_exists(jobid)) { + if (!print_job_exists(snum, jobid)) { errcode = NERR_JobNotFound; goto out; } @@ -2204,15 +2207,15 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param switch (function) { case 81: /* delete */ - if (print_job_delete(¤t_user, jobid, &werr)) + if (print_job_delete(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; case 82: /* pause */ - if (print_job_pause(¤t_user, jobid, &werr)) + if (print_job_pause(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; case 83: /* resume */ - if (print_job_resume(¤t_user, jobid, &werr)) + if (print_job_resume(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; } @@ -2313,12 +2316,14 @@ static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,cha char *str1 = param+2; char *str2 = skip_string(str1,1); char *p = skip_string(str2,1); - int jobid; + uint32 jobid; + int snum; int uLevel = SVAL(p,2); int function = SVAL(p,4); int place, errcode; - jobid = SVAL(p,0); + if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) + return False; *rparam_len = 4; *rparam = REALLOC(*rparam,*rparam_len); @@ -2329,7 +2334,7 @@ static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,cha (!check_printjob_info(&desc,uLevel,str2))) return(False); - if (!print_job_exists(jobid)) { + if (!print_job_exists(snum, jobid)) { errcode=NERR_JobNotFound; goto out; } @@ -2341,14 +2346,14 @@ static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,cha /* change job place in the queue, data gives the new place */ place = SVAL(data,0); - if (print_job_set_place(jobid, place)) { + if (print_job_set_place(snum, jobid, place)) { errcode=NERR_Success; } break; case 0xb: /* change print job name, data gives the name */ - if (print_job_set_name(jobid, data)) { + if (print_job_set_name(snum, jobid, data)) { errcode=NERR_Success; } break; @@ -2994,7 +2999,7 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para int count; int i; int snum; - int job; + uint32 jobid; struct pack_desc desc; print_queue_struct *queue=NULL; print_status_struct status; @@ -3011,14 +3016,14 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para if (strcmp(str1,"WWrLh") != 0) return False; if (!check_printjob_info(&desc,uLevel,str2)) return False; - job = SVAL(p,0); - snum = print_job_snum(job); + if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) + return False; if (snum < 0 || !VALID_SNUM(snum)) return(False); count = print_queue_status(snum,&queue,&status); for (i = 0; i < count; i++) { - if (queue[i].job == job) break; + if (queue[i].job == jobid) break; } if (mdrcnt > 0) { @@ -3549,7 +3554,7 @@ static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,cha -struct +const static struct { char *name; int id; diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c index e2c4b43bc3..6b53cc72aa 100644 --- a/source3/smbd/mangle_hash2.c +++ b/source3/smbd/mangle_hash2.c @@ -202,13 +202,13 @@ static BOOL is_mangled_component(const char *name) M_DEBUG(0,("is_mangled_component %s ?\n", name)); - /* the best distinguishing characteristic is the ~ */ - if (name[6] != '~') return False; - /* check the length */ len = strlen(name); if (len > 12 || len < 8) return False; + /* the best distinguishing characteristic is the ~ */ + if (name[6] != '~') return False; + /* check extension */ if (len > 8) { if (name[8] != '.') return False; diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 81c2427a00..2be04fd686 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -23,7 +23,6 @@ extern int Protocol; extern int max_recv; extern fstring global_myworkgroup; -extern fstring remote_machine; BOOL global_encrypted_passwords_negotiated = False; BOOL global_spnego_negotiated = False; struct auth_context *negprot_global_auth_context = NULL; @@ -200,14 +199,11 @@ static int negprot_spnego(char *p) if (lp_security() != SEC_ADS) { blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE"); } else { - ADS_STRUCT *ads; - ads = ads_init_simple(); /* win2000 uses host$@REALM, which we will probably use eventually, but for now this works */ - asprintf(&principal, "HOST/%s@%s", guid, ads->realm); + asprintf(&principal, "HOST/%s@%s", guid, lp_realm()); blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal); free(principal); - ads_destroy(&ads); } memcpy(p, blob.data, blob.length); len = blob.length; @@ -288,10 +284,12 @@ static int reply_nt1(char *inbuf, char *outbuf) if (!negotiate_spnego) { /* Create a token value and add it to the outgoing packet. */ if (global_encrypted_passwords_negotiated) { + /* note that we do not send a challenge at all if + we are using plaintext */ get_challenge(p); + SSVALS(outbuf,smb_vwv16+1,8); + p += 8; } - SSVALS(outbuf,smb_vwv16+1,8); - p += 8; p += srvstr_push(outbuf, p, global_myworkgroup, -1, STR_UNICODE|STR_TERMINATE|STR_NOALIGN); DEBUG(3,("not using SPNEGO\n")); @@ -412,8 +410,17 @@ int reply_negprot(connection_struct *conn, char *p; int bcc = SVAL(smb_buf(inbuf),-2); int arch = ARCH_ALL; + + static BOOL done_negprot = False; + START_PROFILE(SMBnegprot); + if (done_negprot) { + END_PROFILE(SMBnegprot); + exit_server("multiple negprot's are not permitted"); + } + done_negprot = True; + p = smb_buf(inbuf)+1; while (p < (smb_buf(inbuf) + bcc)) { Index++; diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index e0a0da7a75..cf69dfddb0 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -28,19 +28,19 @@ extern BOOL case_preserve; extern BOOL short_case_preserve; static char *known_nt_pipes[] = { - "\\LANMAN", - "\\srvsvc", - "\\samr", - "\\wkssvc", - "\\NETLOGON", - "\\ntlsa", - "\\ntsvcs", - "\\lsass", - "\\lsarpc", - "\\winreg", - "\\spoolss", - "\\netdfs", - NULL + "\\LANMAN", + "\\srvsvc", + "\\samr", + "\\wkssvc", + "\\NETLOGON", + "\\ntlsa", + "\\ntsvcs", + "\\lsass", + "\\lsarpc", + "\\winreg", + "\\spoolss", + "\\netdfs", + NULL }; /* Map generic permissions to file object specific permissions */ @@ -62,184 +62,183 @@ struct generic_mapping file_generic_mapping = { static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_error, char *params, int paramsize, char *pdata, int datasize) { - extern int max_send; - int data_to_send = datasize; - int params_to_send = paramsize; - int useable_space; - char *pp = params; - char *pd = pdata; - int params_sent_thistime, data_sent_thistime, total_sent_thistime; - int alignment_offset = 3; - int data_alignment_offset = 0; - - /* - * Initially set the wcnt area to be 18 - this is true for all - * transNT replies. - */ - - set_message(outbuf,18,0,True); - - if (NT_STATUS_V(nt_error)) { - ERROR_NT(nt_error); - } - - /* - * If there genuinely are no parameters or data to send just send - * the empty packet. - */ - - if(params_to_send == 0 && data_to_send == 0) { - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_nt_replies: send_smb failed."); - return 0; - } - - /* - * When sending params and data ensure that both are nicely aligned. - * Only do this alignment when there is also data to send - else - * can cause NT redirector problems. - */ - - if (((params_to_send % 4) != 0) && (data_to_send != 0)) - data_alignment_offset = 4 - (params_to_send % 4); - - /* - * Space is bufsize minus Netbios over TCP header minus SMB header. - * The alignment_offset is to align the param bytes on a four byte - * boundary (2 bytes for data len, one byte pad). - * NT needs this to work correctly. - */ - - useable_space = bufsize - ((smb_buf(outbuf)+ - alignment_offset+data_alignment_offset) - - outbuf); - - /* - * useable_space can never be more than max_send minus the - * alignment offset. - */ - - useable_space = MIN(useable_space, - max_send - (alignment_offset+data_alignment_offset)); - - - while (params_to_send || data_to_send) { - - /* - * Calculate whether we will totally or partially fill this packet. - */ - - total_sent_thistime = params_to_send + data_to_send + - alignment_offset + data_alignment_offset; - - /* - * We can never send more than useable_space. - */ - - total_sent_thistime = MIN(total_sent_thistime, useable_space); - - set_message(outbuf, 18, total_sent_thistime, True); - - /* - * Set total params and data to be sent. - */ - - SIVAL(outbuf,smb_ntr_TotalParameterCount,paramsize); - SIVAL(outbuf,smb_ntr_TotalDataCount,datasize); - - /* - * Calculate how many parameters and data we can fit into - * this packet. Parameters get precedence. - */ - - params_sent_thistime = MIN(params_to_send,useable_space); - data_sent_thistime = useable_space - params_sent_thistime; - data_sent_thistime = MIN(data_sent_thistime,data_to_send); - - SIVAL(outbuf,smb_ntr_ParameterCount,params_sent_thistime); - - if(params_sent_thistime == 0) { - SIVAL(outbuf,smb_ntr_ParameterOffset,0); - SIVAL(outbuf,smb_ntr_ParameterDisplacement,0); - } else { - /* - * smb_ntr_ParameterOffset is the offset from the start of the SMB header to the - * parameter bytes, however the first 4 bytes of outbuf are - * the Netbios over TCP header. Thus use smb_base() to subtract - * them from the calculation. - */ - - SIVAL(outbuf,smb_ntr_ParameterOffset, - ((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); - /* - * Absolute displacement of param bytes sent in this packet. - */ - - SIVAL(outbuf,smb_ntr_ParameterDisplacement,pp - params); - } - - /* - * Deal with the data portion. - */ - - SIVAL(outbuf,smb_ntr_DataCount, data_sent_thistime); - - if(data_sent_thistime == 0) { - SIVAL(outbuf,smb_ntr_DataOffset,0); - SIVAL(outbuf,smb_ntr_DataDisplacement, 0); - } else { - /* - * The offset of the data bytes is the offset of the - * parameter bytes plus the number of parameters being sent this time. - */ - - SIVAL(outbuf,smb_ntr_DataOffset,((smb_buf(outbuf)+alignment_offset) - - smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); - SIVAL(outbuf,smb_ntr_DataDisplacement, pd - pdata); - } + extern int max_send; + int data_to_send = datasize; + int params_to_send = paramsize; + int useable_space; + char *pp = params; + char *pd = pdata; + int params_sent_thistime, data_sent_thistime, total_sent_thistime; + int alignment_offset = 3; + int data_alignment_offset = 0; - /* - * Copy the param bytes into the packet. - */ + /* + * Initially set the wcnt area to be 18 - this is true for all + * transNT replies. + */ + + set_message(outbuf,18,0,True); + + if (NT_STATUS_V(nt_error)) + ERROR_NT(nt_error); + + /* + * If there genuinely are no parameters or data to send just send + * the empty packet. + */ + + if(params_to_send == 0 && data_to_send == 0) { + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("send_nt_replies: send_smb failed."); + return 0; + } + + /* + * When sending params and data ensure that both are nicely aligned. + * Only do this alignment when there is also data to send - else + * can cause NT redirector problems. + */ + + if (((params_to_send % 4) != 0) && (data_to_send != 0)) + data_alignment_offset = 4 - (params_to_send % 4); + + /* + * Space is bufsize minus Netbios over TCP header minus SMB header. + * The alignment_offset is to align the param bytes on a four byte + * boundary (2 bytes for data len, one byte pad). + * NT needs this to work correctly. + */ + + useable_space = bufsize - ((smb_buf(outbuf)+ + alignment_offset+data_alignment_offset) - + outbuf); + + /* + * useable_space can never be more than max_send minus the + * alignment offset. + */ + + useable_space = MIN(useable_space, + max_send - (alignment_offset+data_alignment_offset)); - if(params_sent_thistime) - memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); - - /* - * Copy in the data bytes - */ - if(data_sent_thistime) - memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ - data_alignment_offset,pd,data_sent_thistime); + while (params_to_send || data_to_send) { + + /* + * Calculate whether we will totally or partially fill this packet. + */ + + total_sent_thistime = params_to_send + data_to_send + + alignment_offset + data_alignment_offset; + + /* + * We can never send more than useable_space. + */ + + total_sent_thistime = MIN(total_sent_thistime, useable_space); + + set_message(outbuf, 18, total_sent_thistime, True); + + /* + * Set total params and data to be sent. + */ + + SIVAL(outbuf,smb_ntr_TotalParameterCount,paramsize); + SIVAL(outbuf,smb_ntr_TotalDataCount,datasize); + + /* + * Calculate how many parameters and data we can fit into + * this packet. Parameters get precedence. + */ + + params_sent_thistime = MIN(params_to_send,useable_space); + data_sent_thistime = useable_space - params_sent_thistime; + data_sent_thistime = MIN(data_sent_thistime,data_to_send); + + SIVAL(outbuf,smb_ntr_ParameterCount,params_sent_thistime); + + if(params_sent_thistime == 0) { + SIVAL(outbuf,smb_ntr_ParameterOffset,0); + SIVAL(outbuf,smb_ntr_ParameterDisplacement,0); + } else { + /* + * smb_ntr_ParameterOffset is the offset from the start of the SMB header to the + * parameter bytes, however the first 4 bytes of outbuf are + * the Netbios over TCP header. Thus use smb_base() to subtract + * them from the calculation. + */ + + SIVAL(outbuf,smb_ntr_ParameterOffset, + ((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); + /* + * Absolute displacement of param bytes sent in this packet. + */ + + SIVAL(outbuf,smb_ntr_ParameterDisplacement,pp - params); + } + + /* + * Deal with the data portion. + */ + + SIVAL(outbuf,smb_ntr_DataCount, data_sent_thistime); + + if(data_sent_thistime == 0) { + SIVAL(outbuf,smb_ntr_DataOffset,0); + SIVAL(outbuf,smb_ntr_DataDisplacement, 0); + } else { + /* + * The offset of the data bytes is the offset of the + * parameter bytes plus the number of parameters being sent this time. + */ + + SIVAL(outbuf,smb_ntr_DataOffset,((smb_buf(outbuf)+alignment_offset) - + smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); + SIVAL(outbuf,smb_ntr_DataDisplacement, pd - pdata); + } + + /* + * Copy the param bytes into the packet. + */ + + if(params_sent_thistime) + memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); + + /* + * Copy in the data bytes + */ + + if(data_sent_thistime) + memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ + data_alignment_offset,pd,data_sent_thistime); - DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", - params_sent_thistime, data_sent_thistime, useable_space)); - DEBUG(9,("nt_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", - params_to_send, data_to_send, paramsize, datasize)); + DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", + params_sent_thistime, data_sent_thistime, useable_space)); + DEBUG(9,("nt_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", + params_to_send, data_to_send, paramsize, datasize)); - /* Send the packet */ - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_nt_replies: send_smb failed."); + /* Send the packet */ + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("send_nt_replies: send_smb failed."); - pp += params_sent_thistime; - pd += data_sent_thistime; + pp += params_sent_thistime; + pd += data_sent_thistime; - params_to_send -= params_sent_thistime; - data_to_send -= data_sent_thistime; + params_to_send -= params_sent_thistime; + data_to_send -= data_sent_thistime; - /* - * Sanity check - */ + /* + * Sanity check + */ - if(params_to_send < 0 || data_to_send < 0) { - DEBUG(0,("send_nt_replies failed sanity check pts = %d, dts = %d\n!!!", - params_to_send, data_to_send)); - return -1; - } - } + if(params_to_send < 0 || data_to_send < 0) { + DEBUG(0,("send_nt_replies failed sanity check pts = %d, dts = %d\n!!!", + params_to_send, data_to_send)); + return -1; + } + } - return 0; + return 0; } /**************************************************************************** @@ -852,7 +851,7 @@ int reply_ntcreate_and_X(connection_struct *conn, p += 8; SIVAL(p,0,fmode); /* File Attributes. */ p += 4; - SOFF_T(p, 0, SMB_ROUNDUP_ALLOCATION(file_len)); + SOFF_T(p, 0, get_allocation_size(&sbuf)); p += 8; SOFF_T(p,0,file_len); p += 12; @@ -1296,7 +1295,7 @@ static int call_nt_transact_create(connection_struct *conn, p += 8; SIVAL(p,0,fmode); /* File Attributes. */ p += 4; - SOFF_T(p, 0, SMB_ROUNDUP_ALLOCATION(file_len)); + SOFF_T(p, 0, get_allocation_size(&sbuf)); p += 8; SOFF_T(p,0,file_len); @@ -1311,6 +1310,7 @@ static int call_nt_transact_create(connection_struct *conn, /**************************************************************************** Reply to a NT CANCEL request. ****************************************************************************/ + int reply_ntcancel(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { @@ -1332,6 +1332,7 @@ int reply_ntcancel(connection_struct *conn, /**************************************************************************** Reply to an unsolicited SMBNTtranss - just ignore it! ****************************************************************************/ + int reply_nttranss(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { @@ -1345,6 +1346,7 @@ int reply_nttranss(connection_struct *conn, Reply to a notify change - queue the request and don't allow a directory to be opened. ****************************************************************************/ + static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, @@ -1445,107 +1447,107 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, int length, int bufsize, char **ppsetup, char **ppparams, char **ppdata) { - uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); - char *params = *ppparams; - char *data = *ppdata; - prs_struct pd; - SEC_DESC *psd = NULL; - size_t sd_size; - TALLOC_CTX *mem_ctx; + uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); + char *params = *ppparams; + char *data = *ppdata; + prs_struct pd; + SEC_DESC *psd = NULL; + size_t sd_size; + TALLOC_CTX *mem_ctx; - files_struct *fsp = file_fsp(params,0); + files_struct *fsp = file_fsp(params,0); - if(!fsp) - return ERROR_DOS(ERRDOS,ERRbadfid); + if(!fsp) + return ERROR_DOS(ERRDOS,ERRbadfid); - DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name )); + DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name )); - params = Realloc(*ppparams, 4); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); + params = Realloc(*ppparams, 4); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); - *ppparams = params; + *ppparams = params; - if ((mem_ctx = talloc_init()) == NULL) { - DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); - return ERROR_DOS(ERRDOS,ERRnomem); - } + if ((mem_ctx = talloc_init()) == NULL) { + DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); + return ERROR_DOS(ERRDOS,ERRnomem); + } - /* - * Get the permissions to return. - */ + /* + * Get the permissions to return. + */ - if (!lp_nt_acl_support(SNUM(conn))) - sd_size = get_null_nt_acl(mem_ctx, &psd); - else - sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); + if (!lp_nt_acl_support(SNUM(conn))) + sd_size = get_null_nt_acl(mem_ctx, &psd); + else + sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); - if (sd_size == 0) { - talloc_destroy(mem_ctx); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + if (sd_size == 0) { + talloc_destroy(mem_ctx); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size)); + DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size)); - SIVAL(params,0,(uint32)sd_size); + SIVAL(params,0,(uint32)sd_size); - if(max_data_count < sd_size) { + if(max_data_count < sd_size) { - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL, - params, 4, *ppdata, 0); - talloc_destroy(mem_ctx); - return -1; - } + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL, + params, 4, *ppdata, 0); + talloc_destroy(mem_ctx); + return -1; + } - /* - * Allocate the data we will point this at. - */ + /* + * Allocate the data we will point this at. + */ - data = Realloc(*ppdata, sd_size); - if(data == NULL) { - talloc_destroy(mem_ctx); - return ERROR_DOS(ERRDOS,ERRnomem); - } + data = Realloc(*ppdata, sd_size); + if(data == NULL) { + talloc_destroy(mem_ctx); + return ERROR_DOS(ERRDOS,ERRnomem); + } - *ppdata = data; + *ppdata = data; - memset(data, '\0', sd_size); + memset(data, '\0', sd_size); - /* - * Init the parse struct we will marshall into. - */ + /* + * Init the parse struct we will marshall into. + */ - prs_init(&pd, 0, mem_ctx, MARSHALL); + prs_init(&pd, 0, mem_ctx, MARSHALL); - /* - * Setup the prs_struct to point at the memory we just - * allocated. - */ + /* + * Setup the prs_struct to point at the memory we just + * allocated. + */ - prs_give_memory( &pd, data, (uint32)sd_size, False); + prs_give_memory( &pd, data, (uint32)sd_size, False); - /* - * Finally, linearize into the outgoing buffer. - */ + /* + * Finally, linearize into the outgoing buffer. + */ - if(!sec_io_desc( "sd data", &psd, &pd, 1)) { - DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \ + if(!sec_io_desc( "sd data", &psd, &pd, 1)) { + DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \ security descriptor.\n")); - /* - * Return access denied for want of a better error message.. - */ - talloc_destroy(mem_ctx); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + /* + * Return access denied for want of a better error message.. + */ + talloc_destroy(mem_ctx); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - /* - * Now we can delete the security descriptor. - */ + /* + * Now we can delete the security descriptor. + */ - talloc_destroy(mem_ctx); + talloc_destroy(mem_ctx); - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size); - return -1; + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size); + return -1; } /**************************************************************************** @@ -1592,233 +1594,263 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, } /**************************************************************************** - Reply to IOCTL - not implemented - no plans. + Reply to NT IOCTL ****************************************************************************/ - static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, char **ppparams, char **ppdata) + char **ppsetup, int setup_count, + char **ppparams, int parameter_count, + char **ppdata, int data_count) { - static BOOL logged_message = False; + unsigned fnum, control; + static BOOL logged_message; - if(!logged_message) { - DEBUG(3,("call_nt_transact_ioctl: Currently not implemented.\n")); - logged_message = True; /* Only print this once... */ + if (setup_count != 8) { + DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count)); + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } - return ERROR_DOS(ERRSRV,ERRnosupport); + + fnum = SVAL(*ppsetup, 4); + control = IVAL(*ppsetup, 0); + + DEBUG(6,("call_nt_transact_ioctl: fnum=%d control=0x%x\n", + fnum, control)); + + switch (control) { + case NTIOCTL_SET_SPARSE: + /* pretend this succeeded - tho strictly we should + mark the file sparse (if the local fs supports it) + so we can know if we need to pre-allocate or not */ + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); + return -1; + + default: + if (!logged_message) { + logged_message = True; /* Only print this once... */ + DEBUG(3,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n", + control)); + } + } + + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } /**************************************************************************** Reply to a SMBNTtrans. ****************************************************************************/ + int reply_nttrans(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) + char *inbuf,char *outbuf,int length,int bufsize) { - int outsize = 0; + int outsize = 0; #if 0 /* Not used. */ - uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount); - uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount); - uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); + uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount); + uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount); + uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); #endif /* Not used. */ - uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount); - uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount); - uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount); - uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset); - uint32 data_count = IVAL(inbuf,smb_nt_DataCount); - uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset); - uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */ - uint16 function_code = SVAL( inbuf, smb_nt_Function); - char *params = NULL, *data = NULL, *setup = NULL; - uint32 num_params_sofar, num_data_sofar; - START_PROFILE(SMBnttrans); - - if(global_oplock_break && (function_code == NT_TRANSACT_CREATE)) { - /* - * Queue this open message as we are the process of an oplock break. - */ - - DEBUG(2,("reply_nttrans: queueing message NT_TRANSACT_CREATE \ -due to being in oplock break state.\n" )); - - push_oplock_pending_smb_message( inbuf, length); - END_PROFILE(SMBnttrans); - return -1; - } - - if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) { - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRaccess); - } - - outsize = set_message(outbuf,0,0,True); - - /* - * All nttrans messages we handle have smb_wct == 19 + setup_count. - * Ensure this is so as a sanity check. - */ - - if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) { - DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n", - CVAL(inbuf, smb_wct), 19 + (setup_count/2))); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRerror); - } + uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount); + uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount); + uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount); + uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset); + uint32 data_count = IVAL(inbuf,smb_nt_DataCount); + uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset); + uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */ + uint16 function_code = SVAL( inbuf, smb_nt_Function); + char *params = NULL, *data = NULL, *setup = NULL; + uint32 num_params_sofar, num_data_sofar; + START_PROFILE(SMBnttrans); + + if(global_oplock_break && + ((function_code == NT_TRANSACT_CREATE) || + (function_code == NT_TRANSACT_RENAME))) { + /* + * Queue this open message as we are the process of an oplock break. + */ + + DEBUG(2,("reply_nttrans: queueing message code 0x%x \ +due to being in oplock break state.\n", (unsigned int)function_code )); + + push_oplock_pending_smb_message( inbuf, length); + END_PROFILE(SMBnttrans); + return -1; + } + + if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) { + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRSRV,ERRaccess); + } + + outsize = set_message(outbuf,0,0,True); + + /* + * All nttrans messages we handle have smb_wct == 19 + setup_count. + * Ensure this is so as a sanity check. + */ + + if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) { + DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n", + CVAL(inbuf, smb_wct), 19 + (setup_count/2))); + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRSRV,ERRerror); + } - /* Allocate the space for the setup, the maximum needed parameters and data */ - - if(setup_count > 0) - setup = (char *)malloc(setup_count); - if (total_parameter_count > 0) - params = (char *)malloc(total_parameter_count); - if (total_data_count > 0) - data = (char *)malloc(total_data_count); + /* Allocate the space for the setup, the maximum needed parameters and data */ + + if(setup_count > 0) + setup = (char *)malloc(setup_count); + if (total_parameter_count > 0) + params = (char *)malloc(total_parameter_count); + if (total_data_count > 0) + data = (char *)malloc(total_data_count); - if ((total_parameter_count && !params) || (total_data_count && !data) || - (setup_count && !setup)) { + if ((total_parameter_count && !params) || (total_data_count && !data) || + (setup_count && !setup)) { + SAFE_FREE(setup); + SAFE_FREE(params); + SAFE_FREE(data); + DEBUG(0,("reply_nttrans : Out of memory\n")); + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRDOS,ERRnomem); + } + + /* Copy the param and data bytes sent with this request into the params buffer */ + num_params_sofar = parameter_count; + num_data_sofar = data_count; + + if (parameter_count > total_parameter_count || data_count > total_data_count) + exit_server("reply_nttrans: invalid sizes in packet."); + + if(setup) { + memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); + DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count)); + dump_data(10, setup, setup_count); + } + if(params) { + memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); + DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count)); + dump_data(10, params, parameter_count); + } + if(data) { + memcpy( data, smb_base(inbuf) + data_offset, data_count); + DEBUG(10,("reply_nttrans: data_count = %d\n",data_count)); + dump_data(10, data, data_count); + } + + if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { + /* We need to send an interim response then receive the rest + of the parameter/data bytes */ + outsize = set_message(outbuf,0,0,True); + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("reply_nttrans: send_smb failed."); + + while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { + BOOL ret; + + ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); + + if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) { + outsize = set_message(outbuf,0,0,True); + if(ret) { + DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n")); + } else { + DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", + (smb_read_error == READ_ERROR) ? "error" : "timeout" )); + } + SAFE_FREE(params); + SAFE_FREE(data); + SAFE_FREE(setup); + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRSRV,ERRerror); + } + + /* Revise total_params and total_data in case they have changed downwards */ + total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount); + total_data_count = IVAL(inbuf, smb_nts_TotalDataCount); + num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount)); + num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount)); + if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) + exit_server("reply_nttrans2: data overflow in secondary nttrans packet"); + + memcpy( ¶ms[ IVAL(inbuf, smb_nts_ParameterDisplacement)], + smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count); + memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)], + smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count); + } + } + + if (Protocol >= PROTOCOL_NT1) + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME); + + /* Now we must call the relevant NT_TRANS function */ + switch(function_code) { + case NT_TRANSACT_CREATE: + START_PROFILE_NESTED(NT_transact_create); + outsize = call_nt_transact_create(conn, inbuf, outbuf, + length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_create); + break; + case NT_TRANSACT_IOCTL: + START_PROFILE_NESTED(NT_transact_ioctl); + outsize = call_nt_transact_ioctl(conn, inbuf, outbuf, + length, bufsize, + &setup, setup_count, + ¶ms, parameter_count, + &data, data_count); + END_PROFILE_NESTED(NT_transact_ioctl); + break; + case NT_TRANSACT_SET_SECURITY_DESC: + START_PROFILE_NESTED(NT_transact_set_security_desc); + outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, + length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_set_security_desc); + break; + case NT_TRANSACT_NOTIFY_CHANGE: + START_PROFILE_NESTED(NT_transact_notify_change); + outsize = call_nt_transact_notify_change(conn, inbuf, outbuf, + length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_notify_change); + break; + case NT_TRANSACT_RENAME: + START_PROFILE_NESTED(NT_transact_rename); + outsize = call_nt_transact_rename(conn, inbuf, outbuf, + length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_rename); + break; + + case NT_TRANSACT_QUERY_SECURITY_DESC: + START_PROFILE_NESTED(NT_transact_query_security_desc); + outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, + length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_query_security_desc); + break; + default: + /* Error in request */ + DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code)); + SAFE_FREE(setup); + SAFE_FREE(params); + SAFE_FREE(data); + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRSRV,ERRerror); + } + + /* As we do not know how many data packets will need to be + returned here the various call_nt_transact_xxxx calls + must send their own. Thus a call_nt_transact_xxxx routine only + returns a value other than -1 when it wants to send + an error packet. + */ + SAFE_FREE(setup); SAFE_FREE(params); SAFE_FREE(data); - DEBUG(0,("reply_nttrans : Out of memory\n")); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRDOS,ERRnomem); - } - - /* Copy the param and data bytes sent with this request into - the params buffer */ - num_params_sofar = parameter_count; - num_data_sofar = data_count; - - if (parameter_count > total_parameter_count || data_count > total_data_count) - exit_server("reply_nttrans: invalid sizes in packet."); - - if(setup) { - memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); - DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count)); - dump_data(10, setup, setup_count); - } - if(params) { - memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); - DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count)); - dump_data(10, params, parameter_count); - } - if(data) { - memcpy( data, smb_base(inbuf) + data_offset, data_count); - DEBUG(10,("reply_nttrans: data_count = %d\n",data_count)); - dump_data(10, data, data_count); - } - - if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { - /* We need to send an interim response then receive the rest - of the parameter/data bytes */ - outsize = set_message(outbuf,0,0,True); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_nttrans: send_smb failed."); - - while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { - BOOL ret; - - ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); - - if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) { - outsize = set_message(outbuf,0,0,True); - if(ret) { - DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n")); - } else { - DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", - (smb_read_error == READ_ERROR) ? "error" : "timeout" )); - } - SAFE_FREE(params); - SAFE_FREE(data); - SAFE_FREE(setup); END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRerror); - } - - /* Revise total_params and total_data in case they have changed downwards */ - total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount); - total_data_count = IVAL(inbuf, smb_nts_TotalDataCount); - num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount)); - num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount)); - if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) - exit_server("reply_nttrans2: data overflow in secondary nttrans packet"); - - memcpy( ¶ms[ IVAL(inbuf, smb_nts_ParameterDisplacement)], - smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count); - memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)], - smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count); - } - } - - if (Protocol >= PROTOCOL_NT1) - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME); - - /* Now we must call the relevant NT_TRANS function */ - switch(function_code) { - case NT_TRANSACT_CREATE: - START_PROFILE_NESTED(NT_transact_create); - outsize = call_nt_transact_create(conn, inbuf, outbuf, length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_create); - break; - case NT_TRANSACT_IOCTL: - START_PROFILE_NESTED(NT_transact_ioctl); - outsize = call_nt_transact_ioctl(conn, - inbuf, outbuf, length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_ioctl); - break; - case NT_TRANSACT_SET_SECURITY_DESC: - START_PROFILE_NESTED(NT_transact_set_security_desc); - outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_set_security_desc); - break; - case NT_TRANSACT_NOTIFY_CHANGE: - START_PROFILE_NESTED(NT_transact_notify_change); - outsize = call_nt_transact_notify_change(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_notify_change); - break; - case NT_TRANSACT_RENAME: - START_PROFILE_NESTED(NT_transact_rename); - outsize = call_nt_transact_rename(conn, inbuf, outbuf, length, - bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_rename); - break; - - case NT_TRANSACT_QUERY_SECURITY_DESC: - START_PROFILE_NESTED(NT_transact_query_security_desc); - outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_query_security_desc); - break; - default: - /* Error in request */ - DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code)); - SAFE_FREE(setup); - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRerror); - } - - /* As we do not know how many data packets will need to be - returned here the various call_nt_transact_xxxx calls - must send their own. Thus a call_nt_transact_xxxx routine only - returns a value other than -1 when it wants to send - an error packet. - */ - - SAFE_FREE(setup); - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBnttrans); - return outsize; /* If a correct response was needed the call_nt_transact_xxxx - calls have already sent it. If outsize != -1 then it is - returning an error packet. */ + return outsize; /* If a correct response was needed the call_nt_transact_xxxx + calls have already sent it. If outsize != -1 then it is + returning an error packet. */ } diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 82c0cef77d..cfac7cf695 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -89,29 +89,6 @@ void invalidate_all_vuids(void) } } -/**************************************************************************** -return a validated username -****************************************************************************/ -char *validated_username(uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - if (vuser == NULL) - return 0; - return(vuser->user.unix_name); -} - -/**************************************************************************** -return a validated domain -****************************************************************************/ -char *validated_domain(uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - if (vuser == NULL) - return 0; - return(vuser->user.domain); -} - - /**************************************************************************** Create the SID list for this user. ****************************************************************************/ @@ -207,7 +184,7 @@ has been given. vuid is biased by an offset. This allows us to tell random client vuid's (normally zero) from valid vuids. ****************************************************************************/ -int register_vuid(auth_serversupplied_info *server_info, char *smb_name) +int register_vuid(auth_serversupplied_info *server_info, const char *smb_name) { user_struct *vuser = NULL; uid_t uid; @@ -297,7 +274,7 @@ int register_vuid(auth_serversupplied_info *server_info, char *smb_name) /* Create an NT_USER_TOKEN struct for this user. */ vuser->nt_user_token = create_nt_token(vuser->uid, vuser->gid, vuser->n_groups, vuser->groups, vuser->guest, server_info->ptok); - DEBUG(3,("uid %d registered to name %s\n",(int)vuser->uid,vuser->user.unix_name)); + DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",(int)vuser->uid,vuser->user.unix_name, vuser->vuid)); next_vuid++; num_validated_vuids++; @@ -311,8 +288,9 @@ int register_vuid(auth_serversupplied_info *server_info, char *smb_name) } /* Register a home dir service for this user */ - if ((!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir) - && (lp_servicenumber(vuser->user.unix_name) < 0)) { + if ((!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) { + DEBUG(3, ("Adding/updating homes service for user '%s' using home direcotry: '%s'\n", + vuser->user.unix_name, vuser->unix_homedir)); vuser->homes_snum = add_home_service(vuser->user.unix_name, vuser->user.unix_name, vuser->unix_homedir); } else { vuser->homes_snum = -1; @@ -325,7 +303,7 @@ int register_vuid(auth_serversupplied_info *server_info, char *smb_name) /**************************************************************************** add a name to the session users list ****************************************************************************/ -void add_session_user(char *user) +void add_session_user(const char *user) { fstring suser; StrnCpy(suser,user,sizeof(suser)-1); @@ -373,7 +351,7 @@ BOOL user_ok(const char *user,int snum) if (valid) str_list_free (&valid); if (ret && lp_onlyuser(snum)) { - char **user_list = str_list_make (lp_username(snum)); + char **user_list = str_list_make (lp_username(snum), NULL); if (user_list && str_list_substitute(user_list, "%S", lp_servicename(snum))) { ret = user_in_list(user, user_list); } diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 85818d524a..043e33e836 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -2296,7 +2296,7 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo switch(tagtype) { case SMB_ACL_USER_OBJ: perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR); - break; + break; case SMB_ACL_GROUP_OBJ: perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP); break; diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 43d3c6c531..55234ec896 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -152,7 +152,7 @@ static void async_processing(char *buffer, int buffer_len) Returns False on timeout or error. Else returns True. -The timeout is in milli seconds +The timeout is in milliseconds ****************************************************************************/ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) @@ -341,9 +341,9 @@ force write permissions on print services. functions. Any message that has a NULL function is unimplemented - please feel free to contribute implementations! */ -static struct smb_message_struct +const static struct smb_message_struct { - char *name; + const char *name; int (*fn)(connection_struct *conn, char *, char *, int, int); int flags; } @@ -386,7 +386,7 @@ static struct smb_message_struct /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE }, /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER }, /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER }, -/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK}, +/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC }, /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC}, /* 0x27 */ { "SMBioctl",reply_ioctl,0}, /* 0x28 */ { "SMBioctls",NULL,AS_USER}, @@ -399,7 +399,7 @@ static struct smb_message_struct /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC }, /* 0x30 */ { NULL, NULL, 0 }, /* 0x31 */ { NULL, NULL, 0 }, -/* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | QUEUE_IN_OPLOCK | CAN_IPC }, +/* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC }, /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER}, /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER}, /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER}, @@ -611,7 +611,7 @@ static struct smb_message_struct /******************************************************************* dump a prs to a file ********************************************************************/ -static void smb_dump(char *name, int type, char *data, ssize_t len) +static void smb_dump(const char *name, int type, char *data, ssize_t len) { int fd, i; pstring fname; @@ -896,7 +896,7 @@ void process_smb(char *inbuf, char *outbuf) /**************************************************************************** return a string containing the function name of a SMB command ****************************************************************************/ -char *smb_fn_name(int type) +const char *smb_fn_name(int type) { static char *unknown_name = "SMBunknown"; @@ -1228,13 +1228,6 @@ void smbd_process(void) max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); - /* re-initialise the timezone */ - TimeInit(); - - /* register our message handlers */ - message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis); - talloc_init_named("dummy!"); - while (True) { int deadtime = lp_deadtime()*60; int select_timeout = setup_select_timeout(); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 0ccdf7c241..c6a082d7d8 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -38,7 +38,6 @@ extern pstring global_myname; extern int global_oplock_break; unsigned int smb_echo_count = 0; -extern fstring remote_machine; extern BOOL global_encrypted_passwords_negotiated; @@ -53,10 +52,11 @@ int reply_special(char *inbuf,char *outbuf) int msg_flags = CVAL(inbuf,1); pstring name1,name2; - extern fstring local_machine; int len; char name_type = 0; + static BOOL already_got_session = False; + *name1 = *name2 = 0; memset(outbuf,'\0',smb_size); @@ -65,6 +65,11 @@ int reply_special(char *inbuf,char *outbuf) switch (msg_type) { case 0x81: /* session request */ + + if (already_got_session) { + exit_server("multiple session request not permitted"); + } + SCVAL(outbuf,0,0x82); SCVAL(outbuf,3,0); if (name_len(inbuf+4) > 50 || @@ -77,24 +82,19 @@ int reply_special(char *inbuf,char *outbuf) DEBUG(2,("netbios connect: name1=%s name2=%s\n", name1,name2)); - fstrcpy(remote_machine,name2); - remote_machine[15] = 0; - trim_string(remote_machine," "," "); - strlower(remote_machine); - alpha_strcpy(remote_machine,remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1); + name1[15] = 0; - fstrcpy(local_machine,name1); - len = strlen(local_machine); + len = strlen(name2); if (len == 16) { - name_type = local_machine[15]; - local_machine[15] = 0; + name_type = name2[15]; + name2[15] = 0; } - trim_string(local_machine," "," "); - strlower(local_machine); - alpha_strcpy(local_machine,local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1); + + set_local_machine_name(name1); + set_remote_machine_name(name2); DEBUG(2,("netbios connect: local=%s remote=%s\n", - local_machine, remote_machine )); + get_local_machine_name(), get_remote_machine_name() )); if (name_type == 'R') { /* We are being asked for a pathworks session --- @@ -107,7 +107,7 @@ int reply_special(char *inbuf,char *outbuf) of possibly valid usernames if we are operating in share mode security */ if (lp_security() == SEC_SHARE) { - add_session_user(remote_machine); + add_session_user(get_remote_machine_name()); } reload_services(True); @@ -115,6 +115,7 @@ int reply_special(char *inbuf,char *outbuf) claim_connection(NULL,"",MAXSTATUS,True); + already_got_session = True; break; case 0x89: /* session keepalive request @@ -148,7 +149,8 @@ int reply_special(char *inbuf,char *outbuf) int reply_tcon(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - pstring service; + const char *service; + pstring service_buf; pstring password; pstring dev; int outsize = 0; @@ -160,17 +162,19 @@ int reply_tcon(connection_struct *conn, START_PROFILE(SMBtcon); - *service = *password = *dev = 0; + *service_buf = *password = *dev = 0; p = smb_buf(inbuf)+1; - p += srvstr_pull_buf(inbuf, service, p, sizeof(service), STR_TERMINATE) + 1; + p += srvstr_pull_buf(inbuf, service_buf, p, sizeof(service), STR_TERMINATE) + 1; pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1; p += pwlen; p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1; - p = strrchr_m(service,'\\'); + p = strrchr_m(service_buf,'\\'); if (p) { - pstrcpy(service, p+1); + service = p+1; + } else { + service = service_buf; } password_blob = data_blob(password, pwlen+1); @@ -354,10 +358,13 @@ int reply_ioctl(connection_struct *conn, switch (ioctl_code) { case IOCTL_QUERY_JOB_INFO: - SSVAL(p,0,fsp->print_jobid); /* Job number */ + { + uint16 rap_jobid = pjobid_to_rap(SNUM(fsp->conn), fsp->print_jobid); + SSVAL(p,0,rap_jobid); /* Job number */ srvstr_push(outbuf, p+2, global_myname, 15, STR_TERMINATE|STR_ASCII); srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); break; + } } END_PROFILE(SMBioctl); @@ -2744,6 +2751,8 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE); + RESOLVE_DFSPATH(directory, conn, inbuf, outbuf); + status = mkdir_internal(conn, directory); if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status); diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 6f0d0238b0..b2b905cec3 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -38,8 +38,6 @@ extern pstring user_socket_options; extern int dcelogin_atmost_once; #endif /* WITH_DFS */ -extern fstring remote_machine; - /* really we should have a top level context structure that has the client file descriptor as an element. That would require a major rewrite :( @@ -133,7 +131,7 @@ static BOOL open_sockets_inetd(void) smbd_set_server_fd(dup(0)); /* close our standard file descriptors */ - close_low_fds(); + close_low_fds(False); /* Don't close stderr */ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); set_socket_options(smbd_server_fd(), user_socket_options); @@ -151,13 +149,15 @@ static void msg_exit_server(int msg_type, pid_t src, void *buf, size_t len) Open the socket communication. ****************************************************************************/ -static BOOL open_sockets(BOOL is_daemon,int port) +static BOOL open_sockets_smbd(BOOL is_daemon,const char *smb_ports) { int num_interfaces = iface_count(); + int num_sockets = 0; int fd_listenset[FD_SETSIZE]; fd_set listen_set; int s; int i; + char *ports; if (!is_daemon) { return open_sockets_inetd(); @@ -176,73 +176,106 @@ static BOOL open_sockets(BOOL is_daemon,int port) /* Stop zombies */ CatchChild(); - - + FD_ZERO(&listen_set); - if(lp_interfaces() && lp_bind_interfaces_only()) { + /* use a reasonable default set of ports - listing on 445 and 139 */ + if (!smb_ports) { + ports = lp_smb_ports(); + if (!ports || !*ports) { + ports = SMB_PORTS; + } + ports = strdup(ports); + } else { + ports = strdup(smb_ports); + } + + if (lp_interfaces() && lp_bind_interfaces_only()) { /* We have been given an interfaces line, and been told to only bind to those interfaces. Create a socket per interface and bind to only these. */ - if(num_interfaces > FD_SETSIZE) { - DEBUG(0,("open_sockets: Too many interfaces specified to bind to. Number was %d \ -max can be %d\n", - num_interfaces, FD_SETSIZE)); - return False; - } - /* Now open a listen socket for each of the interfaces. */ for(i = 0; i < num_interfaces; i++) { struct in_addr *ifip = iface_n_ip(i); - + fstring tok; + char *ptr; + if(ifip == NULL) { - DEBUG(0,("open_sockets: interface %d has NULL IP address !\n", i)); + DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i)); continue; } - s = fd_listenset[i] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True); - if(s == -1) - return False; - /* ready to listen */ - set_socket_options(s,"SO_KEEPALIVE"); - set_socket_options(s,user_socket_options); + for (ptr=ports; next_token(&ptr, tok, NULL, sizeof(tok)); ) { + unsigned port = atoi(tok); + if (port == 0) continue; + s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True); + if(s == -1) + return False; + + /* ready to listen */ + set_socket_options(s,"SO_KEEPALIVE"); + set_socket_options(s,user_socket_options); - if (listen(s, 5) == -1) { - DEBUG(0,("listen: %s\n",strerror(errno))); - close(s); - return False; + if (listen(s, 5) == -1) { + DEBUG(0,("listen: %s\n",strerror(errno))); + close(s); + return False; + } + FD_SET(s,&listen_set); + + num_sockets++; + if (num_sockets >= FD_SETSIZE) { + DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n")); + return False; + } } - FD_SET(s,&listen_set); } } else { /* Just bind to 0.0.0.0 - accept connections from anywhere. */ + + fstring tok; + char *ptr; + num_interfaces = 1; - /* open an incoming socket */ - s = open_socket_in(SOCK_STREAM, port, 0, - interpret_addr(lp_socket_address()),True); - if (s == -1) - return(False); + for (ptr=ports; next_token(&ptr, tok, NULL, sizeof(tok)); ) { + unsigned port = atoi(tok); + if (port == 0) continue; + /* open an incoming socket */ + s = open_socket_in(SOCK_STREAM, port, 0, + interpret_addr(lp_socket_address()),True); + if (s == -1) + return(False); - /* ready to listen */ - set_socket_options(s,"SO_KEEPALIVE"); - set_socket_options(s,user_socket_options); - - if (listen(s, 5) == -1) { - DEBUG(0,("open_sockets: listen: %s\n", - strerror(errno))); - close(s); - return False; + /* ready to listen */ + set_socket_options(s,"SO_KEEPALIVE"); + set_socket_options(s,user_socket_options); + + if (listen(s, 5) == -1) { + DEBUG(0,("open_sockets_smbd: listen: %s\n", + strerror(errno))); + close(s); + return False; + } + + fd_listenset[num_sockets] = s; + FD_SET(s,&listen_set); + + num_sockets++; + + if (num_sockets >= FD_SETSIZE) { + DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n")); + return False; + } } - - fd_listenset[0] = s; - FD_SET(s,&listen_set); } + SAFE_FREE(ports); + /* Listen to messages */ message_register(MSG_SMB_SAM_SYNC, msg_sam_sync); @@ -293,7 +326,7 @@ max can be %d\n", socklen_t in_addrlen = sizeof(addr); s = -1; - for(i = 0; i < num_interfaces; i++) { + for(i = 0; i < num_sockets; i++) { if(FD_ISSET(fd_listenset[i],&lfds)) { s = fd_listenset[i]; /* Clear this so we don't look @@ -309,7 +342,7 @@ max can be %d\n", continue; if (smbd_server_fd() == -1) { - DEBUG(0,("open_sockets: accept: %s\n", + DEBUG(0,("open_sockets_smbd: accept: %s\n", strerror(errno))); continue; } @@ -318,17 +351,21 @@ max can be %d\n", /* Child code ... */ /* close the listening socket(s) */ - for(i = 0; i < num_interfaces; i++) + for(i = 0; i < num_sockets; i++) close(fd_listenset[i]); /* close our standard file descriptors */ - close_low_fds(); + close_low_fds(False); am_parent = 0; set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); set_socket_options(smbd_server_fd(),user_socket_options); + /* this is needed so that we get decent entries + in smbstatus for port 445 connects */ + set_remote_machine_name(get_socket_addr(smbd_server_fd())); + /* Reset global variables in util.c so that client substitutions will be done correctly in the process. */ @@ -382,8 +419,6 @@ BOOL reload_services(BOOL test) { BOOL ret; - set_register_printer_fn(); - if (lp_loaded()) { pstring fname; pstrcpy(fname,lp_configfile()); @@ -611,7 +646,7 @@ static void usage(char *pname) BOOL is_daemon = False; BOOL interactive = False; BOOL specified_logfile = False; - int port = SMB_PORT; + char *ports = NULL; int opt; pstring logfile; @@ -666,7 +701,7 @@ static void usage(char *pname) break; case 'p': - port = atoi(optarg); + ports = optarg; break; case 'h': @@ -705,7 +740,7 @@ static void usage(char *pname) lp_set_logfile(logfile); } - fstrcpy(remote_machine, "smbd"); + set_remote_machine_name("smbd"); setup_logging(argv[0],interactive); @@ -773,11 +808,6 @@ static void usage(char *pname) init_structs(); - /* don't call winbind for our domain if we are the DC */ - if (lp_domain_logons()) { - winbind_exclude_domain(lp_workgroup()); - } - #ifdef WITH_PROFILE if (!profile_setup(False)) { DEBUG(0,("ERROR: failed to setup profiling\n")); @@ -839,13 +869,15 @@ static void usage(char *pname) start_background_queue(); */ - if (!open_sockets(is_daemon,port)) + if (!open_sockets_smbd(is_daemon,ports)) exit(1); /* * everything after this point is run after the fork() */ + namecache_enable(); + if (!locking_init(0)) exit(1); @@ -889,6 +921,13 @@ static void usage(char *pname) if (!init_change_notify()) exit(1); + /* re-initialise the timezone */ + TimeInit(); + + /* register our message handlers */ + message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis); + talloc_init_named("dummy!"); + smbd_process(); uni_group_cache_shutdown(); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 9ac610ab5a..6f83a2d3b7 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -27,9 +27,7 @@ extern BOOL short_case_preserve; extern BOOL case_mangle; extern BOOL case_sensitive; extern BOOL use_mangled_map; -extern fstring remote_machine; extern userdom_struct current_user_info; -extern fstring remote_machine; /**************************************************************************** @@ -104,7 +102,9 @@ int add_home_service(const char *service, const char *username, const char *home } } - lp_add_home(service, iHomeService, username, homedir); + if (!lp_add_home(service, iHomeService, username, homedir)) { + return -1; + } return lp_servicenumber(service); @@ -347,7 +347,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, } if (lp_guest_only(snum)) { - char *guestname = lp_guestaccount(); + const char *guestname = lp_guestaccount(); guest = True; force = True; pass = getpwnam_alloc(guestname); @@ -521,7 +521,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, pstrcpy(s,lp_pathname(snum)); standard_sub_conn(conn,s,sizeof(s)); string_set(&conn->connectpath,s); - DEBUG(3,("Connect path is %s\n",s)); + DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum))); } /* groups stuff added by ih */ @@ -634,7 +634,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, I have disabled this chdir check (tridge) */ if (vfs_ChDir(conn,conn->connectpath) != 0) { DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n", - remote_machine, conn->client_address, + get_remote_machine_name(), conn->client_address, conn->connectpath,strerror(errno))); change_to_root_user(); yield_connection(conn, lp_servicename(SNUM(conn))); @@ -645,7 +645,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, #else /* the alternative is just to check the directory exists */ if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) { - DEBUG(0,("%s is not a directory\n", conn->connectpath)); + DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn)))); change_to_root_user(); yield_connection(conn, lp_servicename(SNUM(conn))); conn_free(conn); @@ -674,7 +674,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, */ if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { - dbgtext( "%s (%s) ", remote_machine, conn->client_address ); + dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address ); dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) ); dbgtext( "initially as user %s ", user ); dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); @@ -759,6 +759,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, vuser = get_valid_user_struct(vuid); if (!vuser) { DEBUG(1,("make_connection: refusing to connect with no session setup\n")); + *status = NT_STATUS_ACCESS_DENIED; return NULL; } } @@ -773,12 +774,15 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, if (strequal(service_in,HOMES_NAME)) { if(lp_security() != SEC_SHARE) { DATA_BLOB no_pw = data_blob(NULL, 0); - if (vuser->homes_snum != -1) { - DEBUG(5, ("making a connection to [homes] service created at session setup time\n")); - return make_connection_snum(vuser->homes_snum, - vuser, no_pw, - dev, status); + if (vuser->homes_snum == -1) { + DEBUG(2, ("[homes] share not available for this user becouse it was not found or created at session setup time\n")); + *status = NT_STATUS_BAD_NETWORK_NAME; + return NULL; } + DEBUG(5, ("making a connection to [homes] service created at session setup time\n")); + return make_connection_snum(vuser->homes_snum, + vuser, no_pw, + dev, status); } else { /* Security = share. Try with current_user_info.smb_name * as the username. */ @@ -797,7 +801,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, } } } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1) - && strequal(service, lp_servicename(vuser->homes_snum))) { + && strequal(service_in, lp_servicename(vuser->homes_snum))) { DATA_BLOB no_pw = data_blob(NULL, 0); DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service)); return make_connection_snum(vuser->homes_snum, @@ -819,7 +823,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, } DEBUG(0,("%s (%s) couldn't find service %s\n", - remote_machine, client_addr(), service)); + get_remote_machine_name(), client_addr(), service)); *status = NT_STATUS_BAD_NETWORK_NAME; return NULL; } @@ -841,7 +845,7 @@ void close_cnum(connection_struct *conn, uint16 vuid) change_to_root_user(); DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n", - remote_machine,conn->client_address, + get_remote_machine_name(),conn->client_address, lp_servicename(SNUM(conn)))); if (conn->vfs_ops.disconnect != NULL) { diff --git a/source3/smbd/session.c b/source3/smbd/session.c index dade953ec1..54b7a24b07 100644 --- a/source3/smbd/session.c +++ b/source3/smbd/session.c @@ -27,21 +27,22 @@ #include "includes.h" -extern fstring remote_machine; - static TDB_CONTEXT *tdb; /* called when a session is created */ BOOL session_claim(user_struct *vuser) { - int i; + int i = 0; TDB_DATA data; struct sessionid sessionid; uint32 pid = (uint32)sys_getpid(); TDB_DATA key; fstring keystr; char * hostname; + int tdb_store_flag; /* If using utmp, we do an inital 'lock hold' store, + but we don't need this if we are just using the + (unique) pid/vuid combination */ - vuser->session_id = 0; + vuser->session_keystr = NULL; /* don't register sessions for the guest user - its just too expensive to go through pam session code for browsing etc */ @@ -63,18 +64,37 @@ BOOL session_claim(user_struct *vuser) data.dptr = NULL; data.dsize = 0; - for (i=1;ivuid); + slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, + SESSION_TEMPLATE, (long unsigned int)sys_getpid(), + vuser->vuid); + key.dptr = keystr; key.dsize = strlen(keystr)+1; - - if (tdb_store(tdb, key, data, TDB_INSERT) == 0) break; - } - - if (i == MAX_SESSION_ID) { - DEBUG(1,("session_claim: out of session IDs (max is %d)\n", - MAX_SESSION_ID)); - return False; + + tdb_store_flag = TDB_REPLACE; } /* If 'hostname lookup' == yes, then do the DNS lookup. This is @@ -90,24 +110,25 @@ BOOL session_claim(user_struct *vuser) fstrcpy(sessionid.username, vuser->user.unix_name); fstrcpy(sessionid.hostname, hostname); - slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, SESSION_TEMPLATE, i); - sessionid.id_num = i; + sessionid.id_num = i; /* Only valid for utmp sessions */ sessionid.pid = pid; sessionid.uid = vuser->uid; sessionid.gid = vuser->gid; - fstrcpy(sessionid.remote_machine, remote_machine); + fstrcpy(sessionid.remote_machine, get_remote_machine_name()); fstrcpy(sessionid.ip_addr, client_addr()); if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) { DEBUG(1,("pam_session rejected the session for %s [%s]\n", sessionid.username, sessionid.id_str)); - tdb_delete(tdb, key); + if (tdb_store_flag == TDB_MODIFY) { + tdb_delete(tdb, key); + } return False; } data.dptr = (char *)&sessionid; data.dsize = sizeof(sessionid); - if (tdb_store(tdb, key, data, TDB_MODIFY) != 0) { + if (tdb_store(tdb, key, data, tdb_store_flag) != 0) { DEBUG(1,("session_claim: unable to create session id record\n")); return False; } @@ -119,7 +140,11 @@ BOOL session_claim(user_struct *vuser) } #endif - vuser->session_id = i; + vuser->session_keystr = strdup(keystr); + if (!vuser->session_keystr) { + DEBUG(0, ("session_claim: strdup() failed for session_keystr\n")); + return False; + } return True; } @@ -129,18 +154,15 @@ void session_yield(user_struct *vuser) TDB_DATA dbuf; struct sessionid sessionid; TDB_DATA key; - fstring keystr; if (!tdb) return; - if (vuser->session_id == 0) { + if (!vuser->session_keystr) { return; } - slprintf(keystr, sizeof(keystr)-1, "ID/%d", vuser->session_id); - - key.dptr = keystr; - key.dsize = strlen(keystr)+1; + key.dptr = vuser->session_keystr; + key.dsize = strlen(vuser->session_keystr)+1; dbuf = tdb_fetch(tdb, key); diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 867b00ff5c..77f93812dd 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -3,6 +3,7 @@ handle SMBsessionsetup Copyright (C) Andrew Tridgell 1998-2001 Copyright (C) Andrew Bartlett 2001 + Copyright (C) Jim McDonough 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -122,6 +123,12 @@ static int reply_spnego_kerberos(connection_struct *conn, ads = ads_init_simple(); + if (!ads) { + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + + ads->auth.realm = strdup(lp_realm()); + ret = ads_verify_ticket(ads, &ticket, &client, &auth_data); if (!NT_STATUS_IS_OK(ret)) { DEBUG(1,("Failed to verify incoming ticket!\n")); @@ -139,7 +146,7 @@ static int reply_spnego_kerberos(connection_struct *conn, } *p = 0; - if (strcasecmp(p+1, ads->realm) != 0) { + if (strcasecmp(p+1, ads->auth.realm) != 0) { DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1)); if (!lp_allow_trusted_domains()) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); @@ -200,7 +207,7 @@ static int reply_spnego_kerberos(connection_struct *conn, send a security blob via a session setup reply ****************************************************************************/ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, - DATA_BLOB blob) + DATA_BLOB blob, uint32 errcode) { char *p; @@ -209,7 +216,7 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end that we aren't finished yet */ - SIVAL(outbuf, smb_rcls, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED)); + SIVAL(outbuf, smb_rcls, errcode); SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */ SSVAL(outbuf, smb_vwv3, blob.length); p = smb_buf(outbuf); @@ -236,11 +243,12 @@ static int reply_spnego_negotiate(connection_struct *conn, DATA_BLOB secblob; int i; uint32 ntlmssp_command, neg_flags, chal_flags; - DATA_BLOB chal, spnego_chal, extra_data; + DATA_BLOB chal, spnego_chal; const uint8 *cryptkey; BOOL got_kerberos = False; NTSTATUS nt_status; extern pstring global_myname; + char *cliname=NULL, *domname=NULL; /* parse out the OIDs and the first sec blob */ if (!parse_negTokenTarg(blob1, OIDs, &secblob)) { @@ -258,7 +266,7 @@ static int reply_spnego_negotiate(connection_struct *conn, DEBUG(3,("Got secblob of size %d\n", secblob.length)); #ifdef HAVE_KRB5 - if (got_kerberos) { + if (got_kerberos && (SEC_ADS == lp_security())) { int ret = reply_spnego_kerberos(conn, inbuf, outbuf, length, bufsize, &secblob); data_blob_free(&secblob); @@ -271,19 +279,16 @@ static int reply_spnego_negotiate(connection_struct *conn, file_save("secblob.dat", secblob.data, secblob.length); #endif - if (!msrpc_parse(&secblob, "CddB", + if (!msrpc_parse(&secblob, "CddAA", "NTLMSSP", &ntlmssp_command, &neg_flags, - &extra_data)) { + &cliname, + &domname)) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - DEBUG(5, ("Extra data: \n")); - dump_data(5, extra_data.data, extra_data.length); - data_blob_free(&secblob); - data_blob_free(&extra_data); if (ntlmssp_command != NTLMSSP_NEGOTIATE) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); @@ -307,41 +312,44 @@ static int reply_spnego_negotiate(connection_struct *conn, return the flags we want. Obviously this is not correct */ chal_flags = NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_LM_KEY | + NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_CHAL_TARGET_INFO; { - DATA_BLOB domain_blob, netbios_blob, realm_blob; + DATA_BLOB domain_blob, struct_blob; + fstring dnsname, dnsdomname; msrpc_gen(&domain_blob, "U", lp_workgroup()); - msrpc_gen(&netbios_blob, - "U", - global_myname); - - msrpc_gen(&realm_blob, - "U", - lp_realm()); - + fstrcpy(dnsdomname, lp_realm()); + strlower(dnsdomname); + + fstrcpy(dnsname, global_myname); + fstrcat(dnsname, "."); + fstrcat(dnsname, lp_realm()); + strlower(dnsname); - msrpc_gen(&chal, "CddddbBBBB", + msrpc_gen(&struct_blob, "aaaaa", + 2, lp_workgroup(), + 1, global_myname, + 4, dnsdomname, + 3, dnsname, + 0, ""); + + msrpc_gen(&chal, "CdUdbddB", "NTLMSSP", NTLMSSP_CHALLENGE, - 0, - 0x30, /* ?? */ + lp_workgroup(), chal_flags, cryptkey, 8, - domain_blob.data, domain_blob.length, - domain_blob.data, domain_blob.length, - netbios_blob.data, netbios_blob.length, - realm_blob.data, realm_blob.length); + 0, 0, + struct_blob.data, struct_blob.length); data_blob_free(&domain_blob); - data_blob_free(&netbios_blob); - data_blob_free(&realm_blob); + data_blob_free(&struct_blob); } if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) { @@ -351,7 +359,7 @@ static int reply_spnego_negotiate(connection_struct *conn, } /* now tell the client to send the auth packet */ - reply_sesssetup_blob(conn, outbuf, spnego_chal); + reply_sesssetup_blob(conn, outbuf, spnego_chal, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED)); data_blob_free(&chal); data_blob_free(&spnego_chal); @@ -368,7 +376,7 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, DATA_BLOB blob1) { - DATA_BLOB auth; + DATA_BLOB auth, response; char *workgroup = NULL, *user = NULL, *machine = NULL; DATA_BLOB lmhash, nthash, sess_key; DATA_BLOB plaintext_password = data_blob(NULL, 0); @@ -413,6 +421,13 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n", user, workgroup, machine, lmhash.length, nthash.length)); + /* the client has given us its machine name (which we otherwise would not get on port 445). + we need to possibly reload smb.conf if smb.conf includes depend on the machine name */ + + set_remote_machine_name(machine); + + reload_services(True); + #if 0 file_save("nthash1.dat", nthash.data, nthash.length); file_save("lmhash1.dat", lmhash.data, lmhash.length); @@ -481,8 +496,12 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, SSVAL(outbuf,smb_uid,sess_vuid); SSVAL(inbuf,smb_uid,sess_vuid); - - return chain_reply(inbuf,outbuf,length,bufsize); + + response = spnego_gen_auth_response(); + reply_sesssetup_blob(conn, outbuf, response, 0); + + /* and tell smbd that we have already replied to this packet */ + return -1; } @@ -594,7 +613,6 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, extern BOOL global_encrypted_passwords_negotiated; extern BOOL global_spnego_negotiated; extern int Protocol; - extern fstring remote_machine; extern userdom_struct current_user_info; extern int max_send; @@ -630,8 +648,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, if (Protocol < PROTOCOL_NT1) { uint16 passlen1 = SVAL(inbuf,smb_vwv7); - if (passlen1 > MAX_PASS_LEN) { - return ERROR_DOS(ERRDOS,ERRbuftoosmall); + if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) { + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } if (doencrypt) { @@ -665,13 +683,6 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, } } - if (passlen1 > MAX_PASS_LEN) { - return ERROR_DOS(ERRDOS,ERRbuftoosmall); - } - - passlen1 = MIN(passlen1, MAX_PASS_LEN); - passlen2 = MIN(passlen2, MAX_PASS_LEN); - if (!doencrypt) { /* both Win95 and WinNT stuff up the password lengths for non-encrypting systems. Uggh. @@ -689,19 +700,29 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, passlen2 = 0; } + /* check for nasty tricks */ + if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) { + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + + if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) { + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + /* Save the lanman2 password and the NT md4 password. */ if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) { doencrypt = False; } - + if (doencrypt) { lm_resp = data_blob(p, passlen1); nt_resp = data_blob(p+passlen1, passlen2); } else { - plaintext_password = data_blob(p, passlen1+1); - /* Ensure null termination */ - plaintext_password.data[passlen1] = 0; + pstring pass; + srvstr_pull(inbuf, pass, smb_buf(inbuf), + sizeof(pass), passlen1, STR_TERMINATE); + plaintext_password = data_blob(pass, strlen(pass)+1); } p += passlen1 + passlen2; @@ -720,7 +741,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine)); + DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name())); if (*user) { if (global_spnego_negotiated) { diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index f1dfb39aac..a66c029286 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -30,6 +30,19 @@ extern int global_oplock_break; extern uint32 global_client_caps; extern pstring global_myname; +/* given a stat buffer return the allocated size on disk, taking into + account sparse files */ +SMB_OFF_T get_allocation_size(SMB_STRUCT_STAT *sbuf) +{ + SMB_OFF_T ret; + ret = sbuf->st_blksize * (SMB_OFF_T)sbuf->st_blocks; + ret = SMB_ROUNDUP_ALLOCATION(ret); + return ret; +} + +#define get_file_size(sbuf) (sbuf.st_size) + + /**************************************************************************** Send the required number of replies back. We assume all fields other than the data fields are @@ -256,7 +269,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i return(UNIXERROR(ERRDOS,ERRnoaccess)); } - size = sbuf.st_size; + size = get_file_size(sbuf); fmode = dos_mode(conn,fname,&sbuf); mtime = sbuf.st_mtime; inode = sbuf.st_ino; @@ -453,7 +466,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint32 reskey=0; int prev_dirpos=0; int mode=0; - SMB_OFF_T size = 0; + SMB_OFF_T file_size = 0; SMB_OFF_T allocation_size = 0; uint32 len; time_t mdate=0, adate=0, cdate=0; @@ -565,8 +578,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, continue; } - size = sbuf.st_size; - allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size); + file_size = get_file_size(sbuf); + allocation_size = get_allocation_size(&sbuf); mdate = sbuf.st_mtime; adate = sbuf.st_atime; cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); @@ -578,7 +591,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, } if(mode & aDIR) - size = 0; + file_size = 0; DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname)); @@ -602,7 +615,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, put_dos_date2(p,l1_fdateCreation,cdate); put_dos_date2(p,l1_fdateLastAccess,adate); put_dos_date2(p,l1_fdateLastWrite,mdate); - SIVAL(p,l1_cbFile,(uint32)size); + SIVAL(p,l1_cbFile,(uint32)file_size); SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size); SSVAL(p,l1_attrFile,mode); p += l1_achName; @@ -621,7 +634,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, put_dos_date2(p,l2_fdateCreation,cdate); put_dos_date2(p,l2_fdateLastAccess,adate); put_dos_date2(p,l2_fdateLastWrite,mdate); - SIVAL(p,l2_cbFile,(uint32)size); + SIVAL(p,l2_cbFile,(uint32)file_size); SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size); SSVAL(p,l2_attrFile,mode); SIVAL(p,l2_cbList,0); /* No extended attributes */ @@ -641,7 +654,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, put_long_date(p,adate); p += 8; put_long_date(p,mdate); p += 8; put_long_date(p,mdate); p += 8; - SOFF_T(p,0,size); + SOFF_T(p,0,file_size); SOFF_T(p,8,allocation_size); p += 16; SIVAL(p,0,nt_extmode); p += 4; @@ -675,7 +688,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, put_long_date(p,adate); p += 8; put_long_date(p,mdate); p += 8; put_long_date(p,mdate); p += 8; - SOFF_T(p,0,size); + SOFF_T(p,0,file_size); SOFF_T(p,8,allocation_size); p += 16; SIVAL(p,0,nt_extmode); p += 4; @@ -696,7 +709,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, put_long_date(p,adate); p += 8; put_long_date(p,mdate); p += 8; put_long_date(p,mdate); p += 8; - SOFF_T(p,0,size); + SOFF_T(p,0,file_size); SOFF_T(p,8,allocation_size); p += 16; SIVAL(p,0,nt_extmode); p += 4; @@ -735,14 +748,14 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ - SOFF_T(p,0,sbuf.st_size); /* File size 64 Bit */ + SOFF_T(p,0,get_file_size(sbuf)); /* File size 64 Bit */ p+= 8; #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) SOFF_T(p,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ #else /* Can't get the value - fake it using size. */ - SOFF_T(p,0,sbuf.st_size); /* Number of bytes used on disk - 64 Bit */ + SOFF_T(p,0,get_file_size(sbuf)); /* Number of bytes used on disk - 64 Bit */ #endif p+= 8; @@ -1528,7 +1541,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, uint16 tran_call = SVAL(inbuf, smb_setup0); uint16 info_level; int mode=0; - SMB_OFF_T size=0; + SMB_OFF_T file_size=0; SMB_OFF_T allocation_size=0; unsigned int data_size; SMB_STRUCT_STAT sbuf; @@ -1643,10 +1656,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn, mode = dos_mode(conn,fname,&sbuf); fullpathname = fname; - size = sbuf.st_size; - allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size); + file_size = get_file_size(sbuf); + allocation_size = get_allocation_size(&sbuf); if (mode & aDIR) - size = 0; + file_size = 0; params = Realloc(*pparams,2); if (params == NULL) @@ -1692,7 +1705,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, put_dos_date2(pdata,l1_fdateCreation,c_time); put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */ - SIVAL(pdata,l1_cbFile,(uint32)size); + SIVAL(pdata,l1_cbFile,(uint32)file_size); SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size); SSVAL(pdata,l1_attrFile,mode); SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */ @@ -1703,7 +1716,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, put_dos_date2(pdata,0,c_time); put_dos_date2(pdata,4,sbuf.st_atime); put_dos_date2(pdata,8,sbuf.st_mtime); - SIVAL(pdata,12,(uint32)size); + SIVAL(pdata,12,(uint32)file_size); SIVAL(pdata,16,(uint32)allocation_size); SIVAL(pdata,20,mode); break; @@ -1747,9 +1760,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_STANDARD_INFO: data_size = 24; - /* Fake up allocation size. */ SOFF_T(pdata,0,allocation_size); - SOFF_T(pdata,8,size); + SOFF_T(pdata,8,file_size); SIVAL(pdata,16,sbuf.st_nlink); SCVAL(pdata,20,0); SCVAL(pdata,21,(mode&aDIR)?1:0); @@ -1794,7 +1806,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_QUERY_FILE_END_OF_FILEINFO: data_size = 8; - SOFF_T(pdata,0,size); + SOFF_T(pdata,0,file_size); break; case SMB_QUERY_FILE_ALL_INFO: @@ -1805,7 +1817,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, SIVAL(pdata,32,mode); pdata += 40; SOFF_T(pdata,0,allocation_size); - SOFF_T(pdata,8,size); + SOFF_T(pdata,8,file_size); SIVAL(pdata,16,sbuf.st_nlink); SCVAL(pdata,20,delete_pending); SCVAL(pdata,21,(mode&aDIR)?1:0); @@ -1917,7 +1929,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False); SIVAL(pdata,0,0); /* ??? */ SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */ - SOFF_T(pdata,8,size); + SOFF_T(pdata,8,file_size); SIVAL(pdata,16,allocation_size); SIVAL(pdata,20,0); /* ??? */ data_size = 24 + byte_len; @@ -1925,7 +1937,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, break; case SMB_FILE_COMPRESSION_INFORMATION: - SOFF_T(pdata,0,size); + SOFF_T(pdata,0,allocation_size); SIVAL(pdata,8,0); /* ??? */ SIVAL(pdata,12,0); /* ??? */ data_size = 16; @@ -1937,7 +1949,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, put_long_date(pdata+16,sbuf.st_mtime); /* write time */ put_long_date(pdata+24,sbuf.st_mtime); /* change time */ SIVAL(pdata,32,allocation_size); - SOFF_T(pdata,40,size); + SOFF_T(pdata,40,file_size); SIVAL(pdata,48,mode); SIVAL(pdata,52,0); /* ??? */ data_size = 56; @@ -1957,14 +1969,14 @@ static int call_trans2qfilepathinfo(connection_struct *conn, DEBUG(4,("call_trans2qfilepathinfo: st_mode=%o\n",(int)sbuf.st_mode)); - SOFF_T(pdata,0,sbuf.st_size); /* File size 64 Bit */ + SOFF_T(pdata,0,get_file_size(sbuf)); /* File size 64 Bit */ pdata += 8; #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) SOFF_T(pdata,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ #else /* Can't get the value - fake it using size. */ - SOFF_T(pdata,0,sbuf.st_size); /* Number of bytes used on disk - 64 Bit */ + SOFF_T(pdata,0,get_file_size(sbuf)); /* Number of bytes used on disk - 64 Bit */ #endif pdata += 8; @@ -2246,7 +2258,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, SSVAL(params,0,0); send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); return(-1); - } + } else + return (UNIXERROR(ERRDOS,ERRbadpath)); } else { /* * Original code - this is an open file. @@ -2310,7 +2323,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, sbuf.st_mtime = fsp->pending_modtime; } - size = sbuf.st_size; + size = get_file_size(sbuf); tvs.modtime = sbuf.st_mtime; tvs.actime = sbuf.st_atime; dosmode = dos_mode(conn,fname,&sbuf); @@ -2413,7 +2426,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n", fname, (double)allocation_size )); - if(allocation_size != sbuf.st_size) { + if(allocation_size != get_file_size(sbuf)) { SMB_STRUCT_STAT new_sbuf; DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new allocation size to %.0f\n", @@ -2459,8 +2472,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, if (ret == -1) return ERROR_NT(NT_STATUS_DISK_FULL); - /* Allocate can trucate size... */ - size = new_sbuf.st_size; + /* Allocate can truncate size... */ + size = get_file_size(new_sbuf); } break; @@ -2715,7 +2728,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", * changing the size of a file. */ if (!size) - size = sbuf.st_size; + size = get_file_size(sbuf); } /* @@ -2757,7 +2770,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } } - if(size != sbuf.st_size) { + if (size != get_file_size(sbuf)) { int ret; @@ -2970,9 +2983,11 @@ static int call_trans2ioctl(connection_struct *conn, char* inbuf, { char *pdata = *ppdata; files_struct *fsp = file_fsp(inbuf,smb_vwv15); - + if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) && (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { + uint16 rap_jobid; + pdata = Realloc(*ppdata, 32); if(pdata == NULL) return ERROR_DOS(ERRDOS,ERRnomem); @@ -2981,7 +2996,8 @@ static int call_trans2ioctl(connection_struct *conn, char* inbuf, /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2 CAN ACCEPT THIS IN UNICODE. JRA. */ - SSVAL(pdata,0,fsp->print_jobid); /* Job number */ + rap_jobid = pjobid_to_rap(SNUM(fsp->conn), fsp->print_jobid); /* Job number */ + SSVAL(pdata,0,rap_jobid); /* Job number */ srvstr_push( outbuf, pdata + 2, global_myname, 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */ srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */ send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32); diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index a18f62c9cc..c0bacf8f91 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -440,44 +440,43 @@ BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_N extern pstring global_myname; extern fstring global_myworkgroup; fstring sid; - BOOL ret = False; + BOOL local_lookup = False; *name_type = SID_NAME_UNKNOWN; /* If we are looking up a domain user, make sure it is for the local machine only */ - switch (lp_server_role()) { - case ROLE_DOMAIN_PDC: - case ROLE_DOMAIN_BDC: + if (strequal(global_myname, domain)) { + local_lookup = True; + } else if (lp_server_role() == ROLE_DOMAIN_PDC || + lp_server_role() == ROLE_DOMAIN_PDC) { if (strequal(domain, global_myworkgroup)) { - ret = local_lookup_name(name, psid, name_type); - } - /* No break is deliberate here. JRA. */ - default: - if (ret) { - } else if (strequal(global_myname, domain)) { - ret = local_lookup_name(name, psid, name_type); - } else { - DEBUG(5, ("lookup_name: domain %s is not local\n", domain)); + local_lookup = True; } } - - if (ret) { - DEBUG(10, - ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n", - domain, name, sid_to_string(sid,psid), - sid_type_lookup(*name_type), (unsigned int)*name_type)); - return True; - } else if (winbind_lookup_name(domain, name, psid, name_type)) { - DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n", - domain, name, sid_to_string(sid, psid), - (unsigned int)*name_type)); - return True; + if (local_lookup) { + if (local_lookup_name(name, psid, name_type)) { + DEBUG(10, + ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n", + domain, name, sid_to_string(sid,psid), + sid_type_lookup(*name_type), (unsigned int)*name_type)); + return True; + } + } else { + /* Remote */ + if (winbind_lookup_name(domain, name, psid, name_type)) { + + DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n", + domain, name, sid_to_string(sid, psid), + (unsigned int)*name_type)); + return True; + } } - - DEBUG(10, ("lookup_name: winbind and local lookups for [%s]\\[%s] failed\n", domain, name)); + + DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n", + local_lookup ? "local" : "winbind", domain, name)); return False; } @@ -593,13 +592,17 @@ DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid) was done correctly, False if not. sidtype is set by this function. *****************************************************************/ -BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype) +BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype) { fstring sid_str; /* if we know its local then don't try winbindd */ if (sid_compare_domain(get_global_sam_sid(), psid) == 0) { - return local_sid_to_uid(puid, psid, sidtype); + BOOL result; + become_root(); + result = local_sid_to_uid(puid, psid, sidtype); + unbecome_root(); + return result; } /* (tridge) I commented out the slab of code below in order to support foreign SIDs @@ -665,7 +668,7 @@ BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype) was done correctly, False if not. *****************************************************************/ -BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype) +BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype) { fstring dom_name, name, sid_str; enum SID_NAME_USE name_type; @@ -676,16 +679,21 @@ BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype) * First we must look up the name and decide if this is a group sid. */ + /* if we know its local then don't try winbindd */ + if (sid_compare_domain(get_global_sam_sid(), psid) == 0) { + BOOL result; + become_root(); + result = local_sid_to_gid(pgid, psid, sidtype); + unbecome_root(); + return result; + } + if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) { - DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n", + DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n", sid_to_string(sid_str, psid) )); - if (!local_sid_to_gid(pgid, psid, sidtype)) { - /* this was probably a foreign sid - assume its a group rid - and continue */ - name_type = SID_NAME_DOM_GRP; - } else { - return True; - } + /* this was probably a foreign sid - assume its a group rid + and continue */ + name_type = SID_NAME_DOM_GRP; } /* @@ -696,7 +704,7 @@ BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype) DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n", (unsigned int)name_type )); - return local_sid_to_gid(pgid, psid, sidtype); + return False; } *sidtype = name_type; diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 5e1dc68bdb..a2291eba08 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -3,6 +3,7 @@ Version 1.9. VFS initialisation and support functions Copyright (C) Tim Potter 1999 + Copyright (C) Alexander Bokovoy 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,6 +18,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This work was sponsored by Optifacio Software Services, Inc. */ #include "includes.h" @@ -28,6 +31,12 @@ struct vfs_syminfo { void *fptr; }; +/* + Opaque (final) vfs operations. This is a combination of first-met opaque vfs operations + across all currently processed modules. */ + +static vfs_op_tuple vfs_opaque_ops[SMB_VFS_OP_LAST]; + /* Default vfs hooks. WARNING: The order of these initialisers is very important. They must be in the same order as defined in vfs.h. Change at your own peril. */ @@ -117,58 +126,75 @@ static struct vfs_ops default_vfs_ops = { initialise default vfs hooks ****************************************************************************/ -static BOOL vfs_init_default(connection_struct *conn) +static void vfs_init_default(connection_struct *conn) { DEBUG(3, ("Initialising default vfs hooks\n")); memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops)); - return True; + conn->vfs_private = NULL; } /**************************************************************************** initialise custom vfs hooks ****************************************************************************/ -static BOOL vfs_init_custom(connection_struct *conn) +static BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object) { int vfs_version = -1; - struct vfs_ops *ops, *(*init_fptr)(int *, struct vfs_ops *); + vfs_op_tuple *ops, *(*init_fptr)(int *, const struct vfs_ops *, struct smb_vfs_handle_struct *); + int i; - DEBUG(3, ("Initialising custom vfs hooks from %s\n", lp_vfsobj(SNUM(conn)))); + DEBUG(3, ("Initialising custom vfs hooks from %s\n", vfs_object)); /* Open object file */ - if ((conn->dl_handle = sys_dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW | RTLD_GLOBAL)) == NULL) { - DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), sys_dlerror())); + if ((conn->vfs_private->handle = sys_dlopen(vfs_object, RTLD_NOW)) == NULL) { + DEBUG(0, ("Error opening %s: %s\n", vfs_object, sys_dlerror())); return False; } /* Get handle on vfs_init() symbol */ - init_fptr = (struct vfs_ops *(*)(int *, struct vfs_ops *))sys_dlsym(conn->dl_handle, "vfs_init"); + init_fptr = (vfs_op_tuple *(*)(int *, const struct vfs_ops *, struct smb_vfs_handle_struct *))sys_dlsym(conn->vfs_private->handle, "vfs_init"); if (init_fptr == NULL) { - DEBUG(0, ("No vfs_init() symbol found in %s\n", lp_vfsobj(SNUM(conn)))); + DEBUG(0, ("No vfs_init() symbol found in %s\n", vfs_object)); return False; } /* Initialise vfs_ops structure */ - conn->vfs_ops = default_vfs_ops; - - if ((ops = init_fptr(&vfs_version, &default_vfs_ops)) == NULL) { - DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn)))); - return False; - } - - if (vfs_version != SMB_VFS_INTERFACE_VERSION) { - DEBUG(0, ("vfs_init returned wrong interface version info (was %d, should be %d)\n", - vfs_version, SMB_VFS_INTERFACE_VERSION )); - return False; - } - - if (ops != &conn->vfs_ops) { - memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops)); + if ((ops = init_fptr(&vfs_version, &conn->vfs_ops, conn->vfs_private)) == NULL) { + DEBUG(0, ("vfs_init() function from %s failed\n", vfs_object)); + return False; + } + + if ((vfs_version < SMB_VFS_INTERFACE_CASCADED)) { + DEBUG(0, ("vfs_init() returned wrong interface version info (was %d, should be no less than %d)\n", + vfs_version, SMB_VFS_INTERFACE_VERSION )); + return False; + } + + if ((vfs_version < SMB_VFS_INTERFACE_VERSION)) { + DEBUG(0, ("Warning: vfs_init() states that module confirms interface version #%d, current interface version is #%d.\n\ +Proceeding in compatibility mode, new operations (since version #%d) will fallback to default ones.\n", + vfs_version, SMB_VFS_INTERFACE_VERSION, vfs_version )); + return False; + } + + for(i=0; ops[i].op != NULL; i++) { + DEBUG(3, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer)); + if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) { + /* Check whether this operation was already made opaque by different module */ + if(vfs_opaque_ops[ops[i].type].op == ((void**)&default_vfs_ops)[ops[i].type]) { + /* No, it isn't overloaded yet. Overload. */ + DEBUG(3, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object)); + vfs_opaque_ops[ops[i].type] = ops[i]; + } + } + /* Change current VFS disposition*/ + DEBUG(3, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object)); + ((void**)&conn->vfs_ops)[ops[i].type] = ops[i].op; } return True; @@ -180,21 +206,70 @@ static BOOL vfs_init_custom(connection_struct *conn) BOOL smbd_vfs_init(connection_struct *conn) { + char **vfs_objects, *vfsobj, *vfs_module, *vfs_path; + int nobj, i; + struct smb_vfs_handle_struct *handle; + + /* Normal share - initialise with disk access functions */ + vfs_init_default(conn); + + /* Override VFS functions if 'vfs object' was specified*/ if (*lp_vfsobj(SNUM(conn))) { - - /* Loadable object file */ - - if (!vfs_init_custom(conn)) { - DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed\n")); - return False; + vfsobj = NULL; + for(i=0; ivfs_private = NULL; + for(i=nobj-1; i>=0; i--) { + handle = (struct smb_vfs_handle_struct *) smb_xmalloc(sizeof(smb_vfs_handle_struct)); + /* Loadable object file */ + handle->handle = NULL; + DLIST_ADD(conn->vfs_private, handle) + vfs_module = NULL; + if (vfs_path) { + asprintf(&vfs_module, "%s/%s", vfs_path, vfs_objects[i]); + } else { + asprintf(&vfs_module, "%s", vfs_objects[i]); + } + if (!vfs_init_custom(conn, vfs_module)) { + DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_module)); + string_free(&vfsobj); + SAFE_FREE(vfs_module); + return False; + } + SAFE_FREE(vfs_module); + } + } + string_free(&vfsobj); + return True; } - - return True; } - - /* Normal share - initialise with disk access functions */ - - return vfs_init_default(conn); + return True; +} + +/******************************************************************* + Create vfs_ops reflecting current vfs_opaque_ops +*******************************************************************/ +struct vfs_ops *smb_vfs_get_opaque_ops(void) +{ + int i; + struct vfs_ops *ops; + + ops = smb_xmalloc(sizeof(struct vfs_ops)); + + for(i=0; i