Coverage Report

Created: 2026-05-24 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/smbd/error.c
Line
Count
Source
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
bool use_nt_status(void)
25
0
{
26
0
  return lp_nt_status_support() && (global_client_caps & CAP_STATUS32);
27
0
}
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
void error_packet_set(char *outbuf, uint8_t eclass, uint32_t ecode, NTSTATUS ntstatus, int line, const char *file)
57
0
{
58
0
  bool force_nt_status = False;
59
0
  bool force_dos_status = False;
60
61
0
  if (eclass == (uint8_t)-1) {
62
0
    force_nt_status = True;
63
0
  } else if (NT_STATUS_IS_DOS(ntstatus)) {
64
0
    force_dos_status = True;
65
0
  }
66
67
0
  if (force_nt_status || (!force_dos_status && lp_nt_status_support() && (global_client_caps & CAP_STATUS32))) {
68
    /* We're returning an NT error. */
69
0
    if (NT_STATUS_V(ntstatus) == 0 && eclass) {
70
0
      ntstatus = dos_to_ntstatus(eclass, ecode);
71
0
    }
72
0
    SIVAL(outbuf,smb_rcls,NT_STATUS_V(ntstatus));
73
0
    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
0
    DEBUG(3,("NT error packet at %s(%d) cmd=%d (%s) %s\n",
79
0
       file, line,
80
0
       (int)CVAL(outbuf,smb_com),
81
0
#if defined(WITH_SMB1SERVER)
82
0
       smb_fn_name(CVAL(outbuf,smb_com)),
83
#else
84
       "",
85
#endif
86
0
       nt_errstr(ntstatus)));
87
0
  } else {
88
    /* We're returning a DOS error only,
89
     * nt_status_to_dos() pulls DOS error codes out of the
90
     * NTSTATUS */
91
0
    if (NT_STATUS_IS_DOS(ntstatus) || (eclass == 0 && NT_STATUS_V(ntstatus))) {
92
0
      ntstatus_to_dos(ntstatus, &eclass, &ecode);
93
0
    }
94
95
0
    SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)&~FLAGS2_32_BIT_ERROR_CODES);
96
0
    SSVAL(outbuf,smb_rcls,eclass);
97
0
    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
0
    DEBUG(3,("DOS error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
104
0
        file, line,
105
0
        (int)CVAL(outbuf,smb_com),
106
0
#if defined(WITH_SMB1SERVER)
107
0
        smb_fn_name(CVAL(outbuf,smb_com)),
108
#else
109
        "",
110
#endif
111
0
        eclass,
112
0
        ecode));
113
0
  }
114
0
}
115
116
size_t error_packet(char *outbuf, uint8_t eclass, uint32_t ecode, NTSTATUS ntstatus, int line, const char *file)
117
0
{
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
0
}
122
123
void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
124
        int line, const char *file)
125
0
{
126
0
  TALLOC_FREE(req->outbuf);
127
0
  reply_smb1_outbuf(req, 0, 0);
128
0
  error_packet_set((char *)req->outbuf, 0, 0, ntstatus, line, file);
129
0
}
130
131
/****************************************************************************
132
 Forces a DOS error on the wire.
133
****************************************************************************/
134
135
void reply_force_dos_error(struct smb_request *req, uint8_t eclass, uint32_t ecode,
136
        int line, const char *file)
137
0
{
138
0
  TALLOC_FREE(req->outbuf);
139
0
  reply_smb1_outbuf(req, 0, 0);
140
0
  error_packet_set((char *)req->outbuf,
141
0
      eclass, ecode,
142
0
      NT_STATUS_DOS(eclass, ecode),
143
0
      line,
144
0
      file);
145
0
}
146
147
void reply_both_error(struct smb_request *req, uint8_t eclass, uint32_t ecode,
148
          NTSTATUS status, int line, const char *file)
149
0
{
150
0
  TALLOC_FREE(req->outbuf);
151
0
  reply_smb1_outbuf(req, 0, 0);
152
0
  error_packet_set((char *)req->outbuf, eclass, ecode, status,
153
0
       line, file);
154
0
}
155
156
void reply_openerror(struct smb_request *req, NTSTATUS status)
157
0
{
158
0
  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
0
    reply_botherror(req, NT_STATUS_OBJECT_NAME_COLLISION,
166
0
      ERRDOS, ERRfilexists);
167
0
  } 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
0
  } else {
173
0
    reply_nterror(req, status);
174
0
  }
175
0
}