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 : }
|