LCOV - code coverage report
Current view: top level - source3/smbd - error.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 42 49 85.7 %
Date: 2024-04-21 15:09:00 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          35 : bool use_nt_status(void)
      25             : {
      26          35 :         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      315832 : void error_packet_set(char *outbuf, uint8_t eclass, uint32_t ecode, NTSTATUS ntstatus, int line, const char *file)
      57             : {
      58      315832 :         bool force_nt_status = False;
      59      315832 :         bool force_dos_status = False;
      60             : 
      61      315832 :         if (eclass == (uint8_t)-1) {
      62           0 :                 force_nt_status = True;
      63      315832 :         } else if (NT_STATUS_IS_DOS(ntstatus)) {
      64      262234 :                 force_dos_status = True;
      65             :         }
      66             : 
      67      315832 :         if (force_nt_status || (!force_dos_status && lp_nt_status_support() && (global_client_caps & CAP_STATUS32))) {
      68             :                 /* We're returning an NT error. */
      69       53470 :                 if (NT_STATUS_V(ntstatus) == 0 && eclass) {
      70           0 :                         ntstatus = dos_to_ntstatus(eclass, ecode);
      71             :                 }
      72       53470 :                 SIVAL(outbuf,smb_rcls,NT_STATUS_V(ntstatus));
      73       53470 :                 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       53470 :                 DEBUG(3,("NT error packet at %s(%d) cmd=%d (%s) %s\n",
      79             :                          file, line,
      80             :                          (int)CVAL(outbuf,smb_com),
      81             : #if defined(WITH_SMB1SERVER)
      82             :                          smb_fn_name(CVAL(outbuf,smb_com)),
      83             : #else
      84             :                          "",
      85             : #endif
      86             :                          nt_errstr(ntstatus)));
      87             :         } else {
      88             :                 /* We're returning a DOS error only,
      89             :                  * nt_status_to_dos() pulls DOS error codes out of the
      90             :                  * NTSTATUS */
      91      262362 :                 if (NT_STATUS_IS_DOS(ntstatus) || (eclass == 0 && NT_STATUS_V(ntstatus))) {
      92      262334 :                         ntstatus_to_dos(ntstatus, &eclass, &ecode);
      93             :                 }
      94             : 
      95      262362 :                 SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)&~FLAGS2_32_BIT_ERROR_CODES);
      96      262362 :                 SSVAL(outbuf,smb_rcls,eclass);
      97      262362 :                 SSVAL(outbuf,smb_err,ecode);  
      98             : 
      99             :                 /* This must not start with the word 'error', as this
     100             :                  * is reserved in the subunit stream protocol, causing
     101             :                  * false errors to show up when debugging is turned
     102             :                  * on */
     103      262362 :                 DEBUG(3,("DOS error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
     104             :                           file, line,
     105             :                           (int)CVAL(outbuf,smb_com),
     106             : #if defined(WITH_SMB1SERVER)
     107             :                           smb_fn_name(CVAL(outbuf,smb_com)),
     108             : #else
     109             :                           "",
     110             : #endif
     111             :                           eclass,
     112             :                           ecode));
     113             :         }
     114      315832 : }
     115             : 
     116           0 : size_t error_packet(char *outbuf, uint8_t eclass, uint32_t ecode, NTSTATUS ntstatus, int line, const char *file)
     117             : {
     118           0 :         size_t outsize = srv_smb1_set_message(outbuf,0,0,True);
     119           0 :         error_packet_set(outbuf, eclass, ecode, ntstatus, line, file);
     120           0 :         return outsize;
     121             : }
     122             : 
     123       50530 : void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
     124             :                     int line, const char *file)
     125             : {
     126       50530 :         TALLOC_FREE(req->outbuf);
     127       50530 :         reply_smb1_outbuf(req, 0, 0);
     128       50530 :         error_packet_set((char *)req->outbuf, 0, 0, ntstatus, line, file);
     129       50530 : }
     130             : 
     131             : /****************************************************************************
     132             :  Forces a DOS error on the wire.
     133             : ****************************************************************************/
     134             : 
     135      262222 : void reply_force_dos_error(struct smb_request *req, uint8_t eclass, uint32_t ecode,
     136             :                     int line, const char *file)
     137             : {
     138      262222 :         TALLOC_FREE(req->outbuf);
     139      262222 :         reply_smb1_outbuf(req, 0, 0);
     140      262222 :         error_packet_set((char *)req->outbuf,
     141             :                         eclass, ecode,
     142      262222 :                         NT_STATUS_DOS(eclass, ecode),
     143             :                         line,
     144             :                         file);
     145      262222 : }
     146             : 
     147        1918 : void reply_both_error(struct smb_request *req, uint8_t eclass, uint32_t ecode,
     148             :                       NTSTATUS status, int line, const char *file)
     149             : {
     150        1918 :         TALLOC_FREE(req->outbuf);
     151        1918 :         reply_smb1_outbuf(req, 0, 0);
     152        1918 :         error_packet_set((char *)req->outbuf, eclass, ecode, status,
     153             :                          line, file);
     154        1918 : }
     155             : 
     156        6880 : void reply_openerror(struct smb_request *req, NTSTATUS status)
     157             : {
     158        6880 :         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
     159             :                 /*
     160             :                  * We hit an existing file, and if we're returning DOS
     161             :                  * error codes OBJECT_NAME_COLLISION would map to
     162             :                  * ERRDOS/183, we need to return ERRDOS/80, see bug
     163             :                  * 4852.
     164             :                  */
     165          93 :                 reply_botherror(req, NT_STATUS_OBJECT_NAME_COLLISION,
     166             :                         ERRDOS, ERRfilexists);
     167        6787 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_TOO_MANY_OPENED_FILES)) {
     168             :                 /* EMFILE always seems to be returned as a DOS error.
     169             :                  * See bug 6837. NOTE this forces a DOS error on the wire
     170             :                  * even though it's calling reply_nterror(). */
     171           0 :                 reply_force_doserror(req, ERRDOS, ERRnofids);
     172             :         } else {
     173        6787 :                 reply_nterror(req, status);
     174             :         }
     175        6880 : }

Generated by: LCOV version 1.14