*** empty log message ***
[samba.git] / source / smbd / reply.c
index 424c7d818321a5c6c7212f1abe483434ccf20980..7194f3b14465268cb6782ab26604c75a8102238f 100644 (file)
@@ -73,43 +73,54 @@ int reply_special(char *inbuf,char *outbuf)
        pstring name1,name2;
        extern fstring remote_machine;
        extern fstring local_machine;
-       char *p;
+       int len;
+       char name_type = 0;
        
        *name1 = *name2 = 0;
        
        smb_setlen(outbuf,0);
        
        switch (msg_type) {
-    case 0x81: /* session request */
-      CVAL(outbuf,0) = 0x82;
-      CVAL(outbuf,3) = 0;
-      if (name_len(inbuf+4) > 50 || name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
-             DEBUG(0,("Invalid name length in session request\n"));
-             return(0);
-      }
-      name_extract(inbuf,4,name1);
-      name_extract(inbuf,4 + name_len(inbuf + 4),name2);
+       case 0x81: /* session request */
+               CVAL(outbuf,0) = 0x82;
+               CVAL(outbuf,3) = 0;
+               if (name_len(inbuf+4) > 50 || 
+                   name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
+                       DEBUG(0,("Invalid name length in session request\n"));
+                       return(0);
+               }
+               name_extract(inbuf,4,name1);
+               name_extract(inbuf,4 + name_len(inbuf + 4),name2);
                DEBUG(2,("netbios connect: name1=%s name2=%s\n",
                         name1,name2));      
 
-      fstrcpy(remote_machine,name2);
-      trim_string(remote_machine," "," ");
-      p = strchr(remote_machine,' ');
-      strlower(remote_machine);
-      if (p) *p = 0;
+               fstrcpy(remote_machine,name2);
+               remote_machine[15] = 0;
+               trim_string(remote_machine," "," ");
+               strlower(remote_machine);
 
-      fstrcpy(local_machine,name1);
-      trim_string(local_machine," "," ");
-      p = strchr(local_machine,' ');
-      strlower(local_machine);
-      if (p) *p = 0;
+               fstrcpy(local_machine,name1);
+               len = strlen(local_machine);
+               if (len == 16) {
+                       name_type = local_machine[15];
+                       local_machine[15] = 0;
+               }
+               trim_string(local_machine," "," ");
+               strlower(local_machine);
+
+               if (name_type == 'R') {
+                       /* We are being asked for a pathworks session --- 
+                          no thanks! */
+                       CVAL(outbuf, 0) = 0x83;
+                       break;
+               }
 
-      add_session_user(remote_machine);
+               add_session_user(remote_machine);
 
-      reload_services(True);
-      reopen_logs();
+               reload_services(True);
+               reopen_logs();
 
-      break;
+               break;
                
        case 0x89: /* session keepalive request 
                      (some old clients produce this?) */
@@ -245,7 +256,6 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   int connection_num;
   uint16 vuid = SVAL(inbuf,smb_uid);
   int passlen = SVAL(inbuf,smb_vwv3);
-  BOOL doencrypt = SMBENCRYPT();
 
   *service = *user = *password = *devicename = 0;
 
@@ -264,7 +274,7 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     password[passlen]=0;    
     path = smb_buf(inbuf) + passlen;
 
-    if (!doencrypt || passlen != 24) {
+    if (passlen != 24) {
       if (strequal(password," "))
        *password = 0;
       passlen = strlen(password);
@@ -379,8 +389,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   BOOL computer_id=False;
   static BOOL done_sesssetup = False;
   BOOL doencrypt = SMBENCRYPT();
+  char *domain = "";
 
   *smb_apasswd = 0;
+  *smb_ntpasswd = 0;
   
   smb_bufsize = SVAL(inbuf,smb_vwv2);
   smb_mpxmax = SVAL(inbuf,smb_vwv3);
@@ -395,9 +407,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     }
 
     memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
+    smb_apasswd[smb_apasslen] = 0;
     pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
 
-    if (lp_security() != SEC_SERVER && !doencrypt) {
+    if (!doencrypt && (lp_security() != SEC_SERVER)) {
            smb_apasslen = strlen(smb_apasswd);
     }
   } else {
@@ -431,12 +444,14 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     passlen1 = MIN(passlen1, MAX_PASS_LEN);
     passlen2 = MIN(passlen2, MAX_PASS_LEN);
 
-    if(doencrypt) {
+    if(doencrypt || (lp_security() == SEC_SERVER)) {
       /* Save the lanman2 password and the NT md4 password. */
       smb_apasslen = passlen1;
       memcpy(smb_apasswd,p,smb_apasslen);
+      smb_apasswd[smb_apasslen] = 0;
       smb_ntpasslen = passlen2;
       memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
+      smb_ntpasswd[smb_ntpasslen] = 0;
     } else {
       /* both Win95 and WinNT stuff up the password lengths for
         non-encrypting systems. Uggh. 
@@ -469,8 +484,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     
     p += passlen1 + passlen2;
     fstrcpy(user,p); p = skip_string(p,1);
+    domain = p;
+
     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
-            p,skip_string(p,1),skip_string(p,2)));
+            domain,skip_string(p,1),skip_string(p,2)));
   }
 
 
@@ -479,7 +496,8 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   /* If name ends in $ then I think it's asking about whether a */
   /* computer with that name (minus the $) has access. For now */
   /* say yes to everything ending in $. */
-  if (user[strlen(user) - 1] == '$') {
+  if (user[strlen(user) - 1] == '$')
+  {
 #ifdef NTDOMAIN
     struct smb_passwd *smb_pass; /* To check if machine account exists */
 /* 
@@ -492,15 +510,27 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
    a domain. This may be the source of future bugs if we cannot
    be sure whether to reject this or not.
 */
-   smb_pass = get_smbpwnam(user);
-   if(smb_pass)
+   /* non-null user name indicates search by username not by smb userid */
+   smb_pass = get_smbpwd_entry(user, 0);
+
+   if (!smb_pass)
+   {
+     /* lkclXXXX: if workstation entry doesn't exist, indicate logon failure */
+     DEBUG(4,("Workstation trust account %s doesn't exist.",user));
+     SSVAL(outbuf, smb_flg2, 0xc003); /* PAXX: Someone please unhack this */
+     CVAL(outbuf, smb_reh) = 1; /* PAXX: Someone please unhack this */
+     return(ERROR(NT_STATUS_LOGON_FAILURE, 0xc000)); /* decimal 109 NT error, 0xc000 */
+   }
+   else
    {
      /* PAXX: This is the NO LOGON workstation trust account stuff */
-     DEBUG(4,("Rejecting workstation trust account %s",user));
+     /* lkclXXXX: if the workstation *does* exist, indicate failure differently! */
+     DEBUG(4,("No Workstation trust account %s",user));
      SSVAL(outbuf, smb_flg2, 0xc003); /* PAXX: Someone please unhack this */
      CVAL(outbuf, smb_reh) = 1; /* PAXX: Someone please unhack this */
-     return(ERROR(NT_STATUS_ALLOTTED_SPACE_EXCEEDED, 0xc000)); /* 0x99 NT error, 0xc00 */
+     return(ERROR(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, 0xc000)); /* decimal 409 NT error, 0xc000 */
    }
+
    computer_id = True;
 #else /* not NTDOMAIN, leave this in. PAXX: Someone get rid of this */
     user[strlen(user) - 1] = '\0';
@@ -533,7 +563,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
     guest = True;
 
-  if (!guest && !(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
+  if (!guest && !(lp_security() == SEC_SERVER && 
+                 server_validate(user, domain, 
+                                 smb_apasswd, smb_apasslen, 
+                                 smb_ntpasswd, smb_ntpasslen)) &&
       !check_hosts_equiv(user))
     {
 
@@ -1158,6 +1191,7 @@ int reply_open(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
  
@@ -1175,6 +1209,7 @@ int reply_open(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1220,7 +1255,11 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   int fnum = -1;
   int smb_mode = SVAL(inbuf,smb_vwv3);
   int smb_attr = SVAL(inbuf,smb_vwv5);
-  BOOL oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+  /* Breakout the oplock request bits so we can set the
+     reply bits separately. */
+  BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+  BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+  BOOL oplock_request = ex_oplock_request | core_oplock_request;
 #if 0
   int open_flags = SVAL(inbuf,smb_vwv2);
   int smb_sattr = SVAL(inbuf,smb_vwv4); 
@@ -1254,6 +1293,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1271,6 +1311,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1287,13 +1328,29 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     return(ERROR(ERRDOS,ERRnoaccess));
   }
 
-  if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+  /* If the caller set the extended oplock request bit
+     and we granted one (by whatever means) - set the
+     correct bit for extended oplock reply.
+   */
+
+  if (ex_oplock_request && lp_fake_oplocks(SNUM(cnum))) {
     smb_action |= EXTENDED_OPLOCK_GRANTED;
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
 
-  if(fsp->granted_oplock) {
+  if(ex_oplock_request && fsp->granted_oplock) {
     smb_action |= EXTENDED_OPLOCK_GRANTED;
+  }
+
+  /* If the caller set the core oplock request bit
+     and we granted one (by whatever means) - set the
+     correct bit for core oplock reply.
+   */
+
+  if (core_oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+  }
+
+  if(core_oplock_request && fsp->granted_oplock) {
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
 
@@ -1384,6 +1441,7 @@ int reply_mknew(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1411,6 +1469,7 @@ int reply_mknew(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
  
@@ -1466,6 +1525,7 @@ int reply_ctemp(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1485,6 +1545,7 @@ int reply_ctemp(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1715,8 +1776,10 @@ int reply_readbraw(char *inbuf, char *outbuf)
     int predict=0;
     _smb_setlen(header,nread);
 
+#if USE_READ_PREDICTION
     if (!Files[fnum].can_write)
       predict = read_predict(fd,startpos,header+4,NULL,nread);
+#endif
 
     if ((nread-predict) > 0)
       seek_file(fnum,startpos + predict);
@@ -2259,7 +2322,12 @@ int reply_close(char *inbuf,char *outbuf)
 
   cnum = SVAL(inbuf,smb_tid);
 
+  /* If it's an IPC, pass off to the pipe handler. */
+  if (IS_IPC(cnum))
+    return reply_pipe_close(inbuf,outbuf);
+
   fnum = GETFNUM(inbuf,smb_vwv0);
+
   CHECK_FNUM(fnum,cnum);
 
   if(HAS_CACHED_ERROR(fnum)) {
@@ -2512,15 +2580,19 @@ int reply_printopen(char *inbuf,char *outbuf)
 
   strcpy(fname2,(char *)mktemp(fname));
 
-  if (!check_name(fname2,cnum))
-    return(ERROR(ERRDOS,ERRnoaccess));
+  if (!check_name(fname2,cnum)) {
+         Files[fnum].reserved = False;
+         return(ERROR(ERRDOS,ERRnoaccess));
+  }
 
   /* Open for exclusive use, write only. */
   open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0), 
                    0, NULL, NULL);
 
-  if (!Files[fnum].open)
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
+  if (!Files[fnum].open) {
+         Files[fnum].reserved = False;
+         return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   /* force it to be a print file */
   Files[fnum].print_file = True;
@@ -2607,7 +2679,7 @@ int reply_printqueue(char *inbuf,char *outbuf)
       DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
     }
 
-  if (!become_user(cnum,vuid))
+  if (!become_user(&Connections[cnum], cnum, vuid))
     return(ERROR(ERRSRV,ERRinvnid));
 
   {
@@ -3116,14 +3188,23 @@ int reply_mv(char *inbuf,char *outbuf)
 
            error = ERRnoaccess;
            sprintf(fname,"%s/%s",directory,dname);
-           if (!can_rename(fname,cnum)) continue;
+           if (!can_rename(fname,cnum)) {
+                   DEBUG(6,("rename %s refused\n", fname));
+                   continue;
+           }
            pstrcpy(destname,newname);
 
-           if (!resolve_wildcards(fname,destname)) continue;
+           if (!resolve_wildcards(fname,destname)) {
+                   DEBUG(6,("resolve_wildcards %s %s failed\n", 
+                            fname, destname));
+                   continue;
+           }
 
            if (file_exist(destname,NULL)) {
-             error = 183;
-             continue;
+                   DEBUG(6,("file_exist %s\n", 
+                            destname));
+                   error = 183;
+                   continue;
            }
            if (!sys_rename(fname,destname)) count++;
            DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
@@ -3181,7 +3262,10 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
   open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
                   1,0,0,&Access,&action);
 
-  if (!Files[fnum1].open) return(False);
+  if (!Files[fnum1].open) {
+         Files[fnum1].reserved = False;
+         return(False);
+  }
 
   if (!target_is_directory && count)
     ofun = 1;
@@ -3196,6 +3280,7 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
 
   if (!Files[fnum2].open) {
     close_file(fnum1,False);
+    Files[fnum2].reserved = False;
     return(False);
   }
 
@@ -3418,9 +3503,7 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
   /* Check if this is an oplock break on a file
      we have granted an oplock on.
    */
-  if((locktype == LOCKING_ANDX_OPLOCK_RELEASE) && 
-     (num_ulocks == 0) && (num_locks == 0) &&
-     (CVAL(inbuf,smb_vwv0) == 0xFF))
+  if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
   {
     int token;
     files_struct *fsp = &Files[fnum];
@@ -3441,19 +3524,28 @@ no oplock granted on this file.\n", fnum));
 
     /* Remove the oplock flag from the sharemode. */
     lock_share_entry(fsp->cnum, dev, inode, &token);
-    if(remove_share_oplock( fnum, token)==False)
+    if(remove_share_oplock( fnum, token)==False) {
+           DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
+dev = %x, inode = %x\n", 
+                    fnum, dev, inode));
+           unlock_share_entry(fsp->cnum, dev, inode, token);
+    } else {
+           unlock_share_entry(fsp->cnum, dev, inode, token);
+
+           /* Clear the granted flag and return. */
+           fsp->granted_oplock = False;
+    }
+
+    /* if this is a pure oplock break request then don't send a reply */
+    if (num_locks == 0 && num_ulocks == 0)
     {
-      DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
-dev = %x, inode = %x\n", fnum, dev, inode));
-      unlock_share_entry(fsp->cnum, dev, inode, token);
+      /* Sanity check - ensure a pure oplock break is not a
+         chained request. */
+      if(CVAL(inbuf,smb_vwv0) != 0xff)
+        DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
+                 (unsigned int)CVAL(inbuf,smb_vwv0) ));
       return -1;
     }
-    unlock_share_entry(fsp->cnum, dev, inode, token);
-
-    /* Clear the granted flag and return. */
-
-    fsp->granted_oplock = False;
-    return -1;
   }
 
   /* Data now points at the beginning of the list