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