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