• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/smbd/
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/globals.h"
22
23/* From lib/error.c */
24extern struct unix_error_map unix_dos_nt_errmap[];
25
26bool use_nt_status(void)
27{
28	return lp_nt_status_support() && (global_client_caps & CAP_STATUS32);
29}
30
31/****************************************************************************
32 Create an error packet. Normally called using the ERROR() macro.
33
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).
38
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.
43
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);
48
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).
52
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
55 server.
56****************************************************************************/
57
58void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
59{
60	bool force_nt_status = False;
61	bool force_dos_status = False;
62
63	if (eclass == (uint8)-1) {
64		force_nt_status = True;
65	} else if (NT_STATUS_IS_DOS(ntstatus)) {
66		force_dos_status = True;
67	}
68
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);
73		}
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",
77			 file, line,
78			 (int)CVAL(outbuf,smb_com),
79			 smb_fn_name(CVAL(outbuf,smb_com)),
80			 nt_errstr(ntstatus)));
81	} else {
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);
88		}
89
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);
93
94		DEBUG(3,("error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
95			  file, line,
96			  (int)CVAL(outbuf,smb_com),
97			  smb_fn_name(CVAL(outbuf,smb_com)),
98			  eclass,
99			  ecode));
100	}
101}
102
103int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
104{
105	int outsize = srv_set_message(outbuf,0,0,True);
106	error_packet_set(outbuf, eclass, ecode, ntstatus, line, file);
107	return outsize;
108}
109
110void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
111		    int line, const char *file)
112{
113	TALLOC_FREE(req->outbuf);
114	reply_outbuf(req, 0, 0);
115	error_packet_set((char *)req->outbuf, 0, 0, ntstatus, line, file);
116}
117
118/****************************************************************************
119 Forces a DOS error on the wire.
120****************************************************************************/
121
122void reply_force_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode,
123		    int line, const char *file)
124{
125	TALLOC_FREE(req->outbuf);
126	reply_outbuf(req, 0, 0);
127	error_packet_set((char *)req->outbuf,
128			eclass, ecode,
129			NT_STATUS_DOS(eclass, ecode),
130			line,
131			file);
132}
133
134void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode,
135		      NTSTATUS status, int line, const char *file)
136{
137	TALLOC_FREE(req->outbuf);
138	reply_outbuf(req, 0, 0);
139	error_packet_set((char *)req->outbuf, eclass, ecode, status,
140			 line, file);
141}
142
143void reply_openerror(struct smb_request *req, NTSTATUS status)
144{
145	if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
146		/*
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
150		 * 4852.
151		 */
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);
159	} else {
160		reply_nterror(req, status);
161	}
162}
163