4b6f0448816ebd42a174b980af233fa3925d60ba
[kai/samba.git] / source3 / libsmb / clierror.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client error handling routines
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jelmer Vernooij 2003
6    Copyright (C) Jeremy Allison 2006
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "libsmb/libsmb.h"
24
25 /****************************************************************************
26  Return a description of an SMB error.
27 ****************************************************************************/
28
29 static const char *cli_smb_errstr(struct cli_state *cli)
30 {
31         return smb_dos_errstr(cli->inbuf);
32 }
33
34 /***************************************************************************
35  Return an error message - either an NT error, SMB error or a RAP error.
36  Note some of the NT errors are actually warnings or "informational" errors
37  in which case they can be safely ignored.
38 ****************************************************************************/
39
40 const char *cli_errstr(struct cli_state *cli)
41 {   
42         fstring cli_error_message;
43         uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), errnum;
44         uint8 errclass;
45         char *result;
46
47         if (!cli->initialised) {
48                 fstrcpy(cli_error_message, "[Programmer's error] cli_errstr called on unitialized cli_stat struct!\n");
49                 goto done;
50         }
51
52         /* Case #1: RAP error */
53         if (cli->rap_error) {
54                 strlcpy(cli_error_message, win_errstr(W_ERROR(cli->rap_error)),
55                         sizeof(cli_error_message));
56                 goto done;
57         }
58
59         /* Case #2: 32-bit NT errors */
60         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
61                 NTSTATUS status = NT_STATUS(IVAL(cli->inbuf,smb_rcls));
62
63                 return nt_errstr(status);
64         }
65
66         cli_dos_error(cli, &errclass, &errnum);
67
68         /* Case #3: SMB error */
69
70         return cli_smb_errstr(cli);
71
72  done:
73         result = talloc_strdup(talloc_tos(), cli_error_message);
74         SMB_ASSERT(result);
75         return result;
76 }
77
78
79 /****************************************************************************
80  Return the 32-bit NT status code from the last packet.
81 ****************************************************************************/
82
83 NTSTATUS cli_nt_error(struct cli_state *cli)
84 {
85         int flgs2 = SVAL(cli->inbuf,smb_flg2);
86
87         /* Deal with socket errors first. */
88         if (cli->fd == -1) {
89                 return NT_STATUS_CONNECTION_DISCONNECTED;
90         }
91
92         if (!(flgs2 & FLAGS2_32_BIT_ERROR_CODES)) {
93                 int e_class  = CVAL(cli->inbuf,smb_rcls);
94                 int code  = SVAL(cli->inbuf,smb_err);
95                 return dos_to_ntstatus(e_class, code);
96         }
97
98         return NT_STATUS(IVAL(cli->inbuf,smb_rcls));
99 }
100
101
102 /****************************************************************************
103  Return the DOS error from the last packet - an error class and an error
104  code.
105 ****************************************************************************/
106
107 void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode)
108 {
109         int  flgs2;
110
111         if(!cli->initialised) {
112                 return;
113         }
114
115         if (cli->fd == -1) {
116                 *eclass = ERRDOS;
117                 *ecode = ERRnotconnected;
118                 return;
119         }
120
121         flgs2 = SVAL(cli->inbuf,smb_flg2);
122
123         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
124                 NTSTATUS ntstatus = NT_STATUS(IVAL(cli->inbuf, smb_rcls));
125                 ntstatus_to_dos(ntstatus, eclass, ecode);
126                 return;
127         }
128
129         *eclass  = CVAL(cli->inbuf,smb_rcls);
130         *ecode  = SVAL(cli->inbuf,smb_err);
131 }
132
133
134 /* Return a UNIX errno appropriate for the error received in the last
135    packet. */
136
137 int cli_errno(struct cli_state *cli)
138 {
139         NTSTATUS status;
140
141         if (cli_is_nt_error(cli)) {
142                 status = cli_nt_error(cli);
143                 return map_errno_from_nt_status(status);
144         }
145
146         if (cli_is_dos_error(cli)) {
147                 uint8 eclass;
148                 uint32 ecode;
149
150                 cli_dos_error(cli, &eclass, &ecode);
151                 status = dos_to_ntstatus(eclass, ecode);
152                 return map_errno_from_nt_status(status);
153         }
154
155         /*
156          * Yuck!  A special case for this Vista error.  Since its high-order
157          * byte isn't 0xc0, it doesn't match cli_is_nt_error() above.
158          */
159         status = cli_nt_error(cli);
160         if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
161             return EACCES;
162         }
163
164         /* for other cases */
165         return EINVAL;
166 }
167
168 /* Return true if the last packet was in error */
169
170 bool cli_is_error(struct cli_state *cli)
171 {
172         uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), rcls = 0;
173
174         /* A socket error is always an error. */
175         if (cli->fd == -1) {
176                 return True;
177         }
178
179         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
180                 /* Return error is error bits are set */
181                 rcls = IVAL(cli->inbuf, smb_rcls);
182                 return (rcls & 0xF0000000) == 0xC0000000;
183         }
184
185         /* Return error if error class in non-zero */
186
187         rcls = CVAL(cli->inbuf, smb_rcls);
188         return rcls != 0;
189 }
190
191 /* Return true if the last error was an NT error */
192
193 bool cli_is_nt_error(struct cli_state *cli)
194 {
195         uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
196
197         /* A socket error is always an NT error. */
198         if (cli->fd == -1) {
199                 return True;
200         }
201
202         return cli_is_error(cli) && (flgs2 & FLAGS2_32_BIT_ERROR_CODES);
203 }
204
205 /* Return true if the last error was a DOS error */
206
207 bool cli_is_dos_error(struct cli_state *cli)
208 {
209         uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
210
211         /* A socket error is always a DOS error. */
212         if (cli->fd == -1) {
213                 return True;
214         }
215
216         return cli_is_error(cli) && !(flgs2 & FLAGS2_32_BIT_ERROR_CODES);
217 }
218
219 bool cli_state_is_connected(struct cli_state *cli)
220 {
221         if (cli == NULL) {
222                 return false;
223         }
224
225         if (!cli->initialised) {
226                 return false;
227         }
228
229         if (cli->fd == -1) {
230                 return false;
231         }
232
233         return true;
234 }
235