s3-lib Remove unused dos error codes from errmap_unix
[abartlet/samba.git/.git] / source3 / smbd / error.c
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 {
26         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 void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
57 {
58         bool force_nt_status = False;
59         bool force_dos_status = False;
60
61         if (eclass == (uint8)-1) {
62                 force_nt_status = True;
63         } else if (NT_STATUS_IS_DOS(ntstatus)) {
64                 force_dos_status = True;
65         }
66
67         if (force_nt_status || (!force_dos_status && lp_nt_status_support() && (global_client_caps & CAP_STATUS32))) {
68                 /* We're returning an NT error. */
69                 if (NT_STATUS_V(ntstatus) == 0 && eclass) {
70                         ntstatus = dos_to_ntstatus(eclass, ecode);
71                 }
72                 SIVAL(outbuf,smb_rcls,NT_STATUS_V(ntstatus));
73                 SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)|FLAGS2_32_BIT_ERROR_CODES);
74                 DEBUG(3,("error packet at %s(%d) cmd=%d (%s) %s\n",
75                          file, line,
76                          (int)CVAL(outbuf,smb_com),
77                          smb_fn_name(CVAL(outbuf,smb_com)),
78                          nt_errstr(ntstatus)));
79         } else {
80                 /* We're returning a DOS error only. */
81                 if (NT_STATUS_IS_DOS(ntstatus)) {
82                         eclass = NT_STATUS_DOS_CLASS(ntstatus);
83                         ecode = NT_STATUS_DOS_CODE(ntstatus);
84                 } else  if (eclass == 0 && NT_STATUS_V(ntstatus)) {
85                         ntstatus_to_dos(ntstatus, &eclass, &ecode);
86                 }
87
88                 SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)&~FLAGS2_32_BIT_ERROR_CODES);
89                 SSVAL(outbuf,smb_rcls,eclass);
90                 SSVAL(outbuf,smb_err,ecode);  
91
92                 DEBUG(3,("error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
93                           file, line,
94                           (int)CVAL(outbuf,smb_com),
95                           smb_fn_name(CVAL(outbuf,smb_com)),
96                           eclass,
97                           ecode));
98         }
99 }
100
101 int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file)
102 {
103         int outsize = srv_set_message(outbuf,0,0,True);
104         error_packet_set(outbuf, eclass, ecode, ntstatus, line, file);
105         return outsize;
106 }
107
108 void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus,
109                     int line, const char *file)
110 {
111         TALLOC_FREE(req->outbuf);
112         reply_outbuf(req, 0, 0);
113         error_packet_set((char *)req->outbuf, 0, 0, ntstatus, line, file);
114 }
115
116 /****************************************************************************
117  Forces a DOS error on the wire.
118 ****************************************************************************/
119
120 void reply_force_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode,
121                     int line, const char *file)
122 {
123         TALLOC_FREE(req->outbuf);
124         reply_outbuf(req, 0, 0);
125         error_packet_set((char *)req->outbuf,
126                         eclass, ecode,
127                         NT_STATUS_DOS(eclass, ecode),
128                         line,
129                         file);
130 }
131
132 void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode,
133                       NTSTATUS status, int line, const char *file)
134 {
135         TALLOC_FREE(req->outbuf);
136         reply_outbuf(req, 0, 0);
137         error_packet_set((char *)req->outbuf, eclass, ecode, status,
138                          line, file);
139 }
140
141 void reply_openerror(struct smb_request *req, NTSTATUS status)
142 {
143         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
144                 /*
145                  * We hit an existing file, and if we're returning DOS
146                  * error codes OBJECT_NAME_COLLISION would map to
147                  * ERRDOS/183, we need to return ERRDOS/80, see bug
148                  * 4852.
149                  */
150                 reply_botherror(req, NT_STATUS_OBJECT_NAME_COLLISION,
151                         ERRDOS, ERRfilexists);
152         } else if (NT_STATUS_EQUAL(status, NT_STATUS_TOO_MANY_OPENED_FILES)) {
153                 /* EMFILE always seems to be returned as a DOS error.
154                  * See bug 6837. NOTE this forces a DOS error on the wire
155                  * even though it's calling reply_nterror(). */
156                 reply_force_doserror(req, ERRDOS, ERRnofids);
157         } else {
158                 reply_nterror(req, status);
159         }
160 }