2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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/>.
21 #include "smbd/globals.h"
23 /* From lib/error.c */
24 extern struct unix_error_map unix_dos_nt_errmap
[];
26 bool use_nt_status(void)
28 return lp_nt_status_support() && (global_client_caps
& CAP_STATUS32
);
31 /****************************************************************************
32 Create an error packet. Normally called using the ERROR() macro.
34 Setting eclass and ecode to zero and status to a valid NT error will
35 reply with an NT error if the client supports CAP_STATUS32, otherwise
36 it maps to and returns a DOS error if the client doesn't support CAP_STATUS32.
37 This is the normal mode of calling this function via reply_nterror(req, status).
39 Setting eclass and ecode to non-zero and status to NT_STATUS_OK (0) will map
40 from a DOS error to an NT error and reply with an NT error if the client
41 supports CAP_STATUS32, otherwise it replies with the given DOS error.
42 This mode is currently not used in the server.
44 Setting both eclass, ecode and status to non-zero values allows a non-default
45 mapping from NT error codes to DOS error codes, and will return one or the
46 other depending on the client supporting CAP_STATUS32 or not. This is the
47 path taken by calling reply_botherror(req, eclass, ecode, status);
49 Setting status to NT_STATUS_DOS(eclass, ecode) forces DOS errors even if the
50 client supports CAP_STATUS32. This is the path taken to force a DOS error
51 reply by calling reply_force_doserror(req, eclass, ecode).
53 Setting status only and eclass to -1 forces NT errors even if the client
54 doesn't support CAP_STATUS32. This mode is currently never used in the
56 ****************************************************************************/
58 void error_packet_set(char *outbuf
, uint8 eclass
, uint32 ecode
, NTSTATUS ntstatus
, int line
, const char *file
)
60 bool force_nt_status
= False
;
61 bool force_dos_status
= False
;
63 if (eclass
== (uint8
)-1) {
64 force_nt_status
= True
;
65 } else if (NT_STATUS_IS_DOS(ntstatus
)) {
66 force_dos_status
= True
;
69 if (force_nt_status
|| (!force_dos_status
&& lp_nt_status_support() && (global_client_caps
& CAP_STATUS32
))) {
70 /* We're returning an NT error. */
71 if (NT_STATUS_V(ntstatus
) == 0 && eclass
) {
72 ntstatus
= dos_to_ntstatus(eclass
, ecode
);
74 SIVAL(outbuf
,smb_rcls
,NT_STATUS_V(ntstatus
));
75 SSVAL(outbuf
,smb_flg2
, SVAL(outbuf
,smb_flg2
)|FLAGS2_32_BIT_ERROR_CODES
);
76 DEBUG(3,("error packet at %s(%d) cmd=%d (%s) %s\n",
78 (int)CVAL(outbuf
,smb_com
),
79 smb_fn_name(CVAL(outbuf
,smb_com
)),
80 nt_errstr(ntstatus
)));
82 /* We're returning a DOS error only. */
83 if (NT_STATUS_IS_DOS(ntstatus
)) {
84 eclass
= NT_STATUS_DOS_CLASS(ntstatus
);
85 ecode
= NT_STATUS_DOS_CODE(ntstatus
);
86 } else if (eclass
== 0 && NT_STATUS_V(ntstatus
)) {
87 ntstatus_to_dos(ntstatus
, &eclass
, &ecode
);
90 SSVAL(outbuf
,smb_flg2
, SVAL(outbuf
,smb_flg2
)&~FLAGS2_32_BIT_ERROR_CODES
);
91 SSVAL(outbuf
,smb_rcls
,eclass
);
92 SSVAL(outbuf
,smb_err
,ecode
);
94 DEBUG(3,("error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
96 (int)CVAL(outbuf
,smb_com
),
97 smb_fn_name(CVAL(outbuf
,smb_com
)),
103 int error_packet(char *outbuf
, uint8 eclass
, uint32 ecode
, NTSTATUS ntstatus
, int line
, const char *file
)
105 int outsize
= srv_set_message(outbuf
,0,0,True
);
106 error_packet_set(outbuf
, eclass
, ecode
, ntstatus
, line
, file
);
110 void reply_nt_error(struct smb_request
*req
, NTSTATUS ntstatus
,
111 int line
, const char *file
)
113 TALLOC_FREE(req
->outbuf
);
114 reply_outbuf(req
, 0, 0);
115 error_packet_set((char *)req
->outbuf
, 0, 0, ntstatus
, line
, file
);
118 /****************************************************************************
119 Forces a DOS error on the wire.
120 ****************************************************************************/
122 void reply_force_dos_error(struct smb_request
*req
, uint8 eclass
, uint32 ecode
,
123 int line
, const char *file
)
125 TALLOC_FREE(req
->outbuf
);
126 reply_outbuf(req
, 0, 0);
127 error_packet_set((char *)req
->outbuf
,
129 NT_STATUS_DOS(eclass
, ecode
),
134 void reply_both_error(struct smb_request
*req
, uint8 eclass
, uint32 ecode
,
135 NTSTATUS status
, int line
, const char *file
)
137 TALLOC_FREE(req
->outbuf
);
138 reply_outbuf(req
, 0, 0);
139 error_packet_set((char *)req
->outbuf
, eclass
, ecode
, status
,
143 void reply_openerror(struct smb_request
*req
, NTSTATUS status
)
145 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
147 * We hit an existing file, and if we're returning DOS
148 * error codes OBJECT_NAME_COLLISION would map to
149 * ERRDOS/183, we need to return ERRDOS/80, see bug
152 reply_botherror(req
, NT_STATUS_OBJECT_NAME_COLLISION
,
153 ERRDOS
, ERRfilexists
);
154 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_TOO_MANY_OPENED_FILES
)) {
155 /* EMFILE always seems to be returned as a DOS error.
156 * See bug 6837. NOTE this forces a DOS error on the wire
157 * even though it's calling reply_nterror(). */
158 reply_force_doserror(req
, ERRDOS
, ERRnofids
);
160 reply_nterror(req
, status
);