LCOV - code coverage report
Current view: top level - source3/smbd - error.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 42 49 85.7 %
Date: 2021-08-25 13:27:56 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    error packet handling
       4             :    Copyright (C) Andrew Tridgell 1992-1998
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "smbd/smbd.h"
      22             : #include "smbd/globals.h"
      23             : 
      24          31 : bool use_nt_status(void)
      25             : {
      26          31 :         return lp_nt_status_support() && (global_client_caps & CAP_STATUS32);
      27             : }
      28             : 
      29             : /****************************************************************************
      30             :  Create an error packet. Normally called using the ERROR() macro.
      31             : 
      32             :  Setting eclass and ecode to zero and status to a valid NT error will
      33             :  reply with an NT error if the client supports CAP_STATUS32, otherwise
      34             :  it maps to and returns a DOS error if the client doesn't support CAP_STATUS32.
      35             :  This is the normal mode of calling this function via reply_nterror(req, status).
      36             : 
      37             :  Setting eclass and ecode to non-zero and status to NT_STATUS_OK (0) will map
      38             :  from a DOS error to an NT error and reply with an NT error if the client
      39             :  supports CAP_STATUS32, otherwise it replies with the given DOS error.
      40             :  This mode is currently not used in the server.
      41             : 
      42             :  Setting both eclass, ecode and status to non-zero values allows a non-default
      43             :  mapping from NT error codes to DOS error codes, and will return one or the
      44             :  other depending on the client supporting CAP_STATUS32 or not. This is the
      45             :  path taken by calling reply_botherror(req, eclass, ecode, status);
      46             : 
      47             :  Setting status to NT_STATUS_DOS(eclass, ecode) forces DOS errors even if the
      48             :  client supports CAP_STATUS32. This is the path taken to force a DOS error
      49             :  reply by calling reply_force_doserror(req, eclass, ecode).
      50             : 
      51             :  Setting status only and eclass to -1 forces NT errors even if the client
      52             :  doesn't support CAP_STATUS32. This mode is currently never used in the
      53             :  server.
      54             : ****************************************************************************/
      55             : 
      56      316442 : void error_packet_set(char *outbuf, uint8_t eclass, uint32_t ecode, NTSTATUS ntstatus, int line, const char *file)
      57             : {
      58      316442 :         bool force_nt_status = False;
      59      316442 :         bool force_dos_status = False;
      60             : 
      61      316442 :         if (eclass == (uint8_t)-1) {
      62           0 :                 force_nt_status = True;
      63      316442 :         } else if (NT_STATUS_IS_DOS(ntstatus)) {
      64      262222 :                 force_dos_status = True;
      65             :         }
      66             : 
      67      316442 :         if (force_nt_status || (!force_dos_status && lp_nt_status_support() && (global_client_caps & CAP_STATUS32))) {
      68             :                 /* We're returning an NT error. */
      69       54094 :                 if (NT_STATUS_V(ntstatus) == 0 && eclass) {
      70           0 :                         ntstatus = dos_to_ntstatus(eclass, ecode);
      71             :                 }
      72       54094 :                 SIVAL(outbuf,smb_rcls,NT_STATUS_V(ntstatus));
      73       54094 :                 SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)|FLAGS2_32_BIT_ERROR_CODES);
      74             :                 /* This must not start with the word 'error', as this
      75             :                  * is reserved in the subunit stream protocol, causing
      76             :                  * false errors to show up when debugging is turned
      77             :                  * on */
      78       54094 :                 DEBUG(3,("NT error packet at %s(%d) cmd=%d (%s) %s\n",
      79             :                          file, line,
      80             :                          (int)CVAL(outbuf,smb_com),
      81             :                          smb_fn_name(CVAL(outbuf,smb_com)),
      82             :                          nt_errstr(ntstatus)));
      83             :         } else {
      84             :                 /* We're returning a DOS error only,
      85             :                  * nt_status_to_dos() pulls DOS error codes out of the
      86             :                  * NTSTATUS */
      87      262348 :                 if (NT_STATUS_IS_DOS(ntstatus) || (eclass == 0 && NT_STATUS_V(ntstatus))) {
      88      262320 :                         ntstatus_to_dos(ntstatus, &eclass, &ecode);
      89             :                 }
      90             : 
      91      262348 :                 SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)&~FLAGS2_32_BIT_ERROR_CODES);
      92      262348 :                 SSVAL(outbuf,smb_rcls,eclass);
      93      262348 :                 SSVAL(outbuf,smb_err,ecode);  
      94             : 
      95             :                 /* This must not start with the word 'error', as this
      96             :                  * is reserved in the subunit stream protocol, causing
      97             :                  * false errors to show up when debugging is turned
      98             :                  * on */
      99      262348 :                 DEBUG(3,("DOS error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
     100             :                           file, line,
     101             :                           (int)CVAL(outbuf,smb_com),
     102             :                           smb_fn_name(CVAL(outbuf,smb_com)),
     103             :                           eclass,
     104             :                           ecode));
     105             :         }
     106      316442 : }
     107             : 
     108           0 : size_t error_packet(char *outbuf, uint8_t eclass, uint32_t ecode, NTSTATUS ntstatus, int line, const char *file)
     109             : {
     110           0 :         size_t outsize = srv_set_message(outbuf,0,0,True);
     111           0 :         error_packet_set(outbuf, eclass, ecode, ntstatus, line, file);
     112           0 :         return outsize;
     113             : }
     114             : 
     115       52274 : void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
     116             :                     int line, const char *file)
     117             : {
     118       52274 :         TALLOC_FREE(req->outbuf);
     119       52274 :         reply_outbuf(req, 0, 0);
     120       52274 :         error_packet_set((char *)req->outbuf, 0, 0, ntstatus, line, file);
     121       52274 : }
     122             : 
     123             : /****************************************************************************
     124             :  Forces a DOS error on the wire.
     125             : ****************************************************************************/
     126             : 
     127      262218 : void reply_force_dos_error(struct smb_request *req, uint8_t eclass, uint32_t ecode,
     128             :                     int line, const char *file)
     129             : {
     130      262218 :         TALLOC_FREE(req->outbuf);
     131      262218 :         reply_outbuf(req, 0, 0);
     132      262218 :         error_packet_set((char *)req->outbuf,
     133             :                         eclass, ecode,
     134      262218 :                         NT_STATUS_DOS(eclass, ecode),
     135             :                         line,
     136             :                         file);
     137      262218 : }
     138             : 
     139         769 : void reply_both_error(struct smb_request *req, uint8_t eclass, uint32_t ecode,
     140             :                       NTSTATUS status, int line, const char *file)
     141             : {
     142         769 :         TALLOC_FREE(req->outbuf);
     143         769 :         reply_outbuf(req, 0, 0);
     144         769 :         error_packet_set((char *)req->outbuf, eclass, ecode, status,
     145             :                          line, file);
     146         769 : }
     147             : 
     148        6798 : void reply_openerror(struct smb_request *req, NTSTATUS status)
     149             : {
     150        6798 :         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
     151             :                 /*
     152             :                  * We hit an existing file, and if we're returning DOS
     153             :                  * error codes OBJECT_NAME_COLLISION would map to
     154             :                  * ERRDOS/183, we need to return ERRDOS/80, see bug
     155             :                  * 4852.
     156             :                  */
     157          85 :                 reply_botherror(req, NT_STATUS_OBJECT_NAME_COLLISION,
     158             :                         ERRDOS, ERRfilexists);
     159        6713 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_TOO_MANY_OPENED_FILES)) {
     160             :                 /* EMFILE always seems to be returned as a DOS error.
     161             :                  * See bug 6837. NOTE this forces a DOS error on the wire
     162             :                  * even though it's calling reply_nterror(). */
     163           0 :                 reply_force_doserror(req, ERRDOS, ERRnofids);
     164             :         } else {
     165        6713 :                 reply_nterror(req, status);
     166             :         }
     167        6798 : }

Generated by: LCOV version 1.13