s3: Remove some bogus error mappings
[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  RAP error codes - a small start but will be extended.
27
28  XXX: Perhaps these should move into a common function because they're
29  duplicated in clirap2.c
30
31 *******************************************************/
32
33 static const struct {
34         int err;
35         const char *message;
36 } rap_errmap[] = {
37         {5,    "RAP5: User has insufficient privilege" },
38         {50,   "RAP50: Not supported by server" },
39         {65,   "RAP65: Access denied" },
40         {86,   "RAP86: The specified password is invalid" },
41         {2220, "RAP2220: Group does not exist" },
42         {2221, "RAP2221: User does not exist" },
43         {2226, "RAP2226: Operation only permitted on a Primary Domain Controller"  },
44         {2237, "RAP2237: User is not in group" },
45         {2242, "RAP2242: The password of this user has expired." },
46         {2243, "RAP2243: The password of this user cannot change." },
47         {2244, "RAP2244: This password cannot be used now (password history conflict)." },
48         {2245, "RAP2245: The password is shorter than required." },
49         {2246, "RAP2246: The password of this user is too recent to change."},
50
51         {0, NULL}
52 };  
53
54 /****************************************************************************
55  Return a description of an SMB error.
56 ****************************************************************************/
57
58 static const char *cli_smb_errstr(struct cli_state *cli)
59 {
60         return smb_dos_errstr(cli->inbuf);
61 }
62
63 /****************************************************************************
64  Convert a socket error into an NTSTATUS.
65 ****************************************************************************/
66
67 static NTSTATUS cli_smb_rw_error_to_ntstatus(struct cli_state *cli)
68 {
69         switch(cli->smb_rw_error) {
70                 case SMB_READ_TIMEOUT:
71                         return NT_STATUS_IO_TIMEOUT;
72                 case SMB_READ_EOF:
73                         return NT_STATUS_END_OF_FILE;
74                 /* What we shoud really do for read/write errors is convert from errno. */
75                 /* FIXME. JRA. */
76                 case SMB_READ_ERROR:
77                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
78                 case SMB_WRITE_ERROR:
79                         return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
80                 case SMB_READ_BAD_SIG:
81                         return NT_STATUS_INVALID_PARAMETER;
82                 case SMB_NO_MEMORY:
83                         return NT_STATUS_NO_MEMORY;
84                 default:
85                         break;
86         }
87         return NT_STATUS_UNSUCCESSFUL;
88 }
89
90 /***************************************************************************
91  Return an error message - either an NT error, SMB error or a RAP error.
92  Note some of the NT errors are actually warnings or "informational" errors
93  in which case they can be safely ignored.
94 ****************************************************************************/
95
96 const char *cli_errstr(struct cli_state *cli)
97 {   
98         fstring cli_error_message;
99         uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), errnum;
100         uint8 errclass;
101         int i;
102         char *result;
103
104         if (!cli->initialised) {
105                 fstrcpy(cli_error_message, "[Programmer's error] cli_errstr called on unitialized cli_stat struct!\n");
106                 goto done;
107         }
108
109         /* Was it server socket error ? */
110         if (cli->fd == -1 && cli->smb_rw_error) {
111                 switch(cli->smb_rw_error) {
112                         case SMB_READ_TIMEOUT:
113                                 slprintf(cli_error_message, sizeof(cli_error_message) - 1,
114                                         "Call timed out: server did not respond after %d milliseconds",
115                                         cli->timeout);
116                                 break;
117                         case SMB_READ_EOF:
118                                 slprintf(cli_error_message, sizeof(cli_error_message) - 1,
119                                         "Call returned zero bytes (EOF)" );
120                                 break;
121                         case SMB_READ_ERROR:
122                                 slprintf(cli_error_message, sizeof(cli_error_message) - 1,
123                                         "Read error: %s", strerror(errno) );
124                                 break;
125                         case SMB_WRITE_ERROR:
126                                 slprintf(cli_error_message, sizeof(cli_error_message) - 1,
127                                         "Write error: %s", strerror(errno) );
128                                 break;
129                         case SMB_READ_BAD_SIG:
130                                 slprintf(cli_error_message, sizeof(cli_error_message) - 1,
131                                         "Server packet had invalid SMB signature!");
132                                 break;
133                         case SMB_NO_MEMORY:
134                                 slprintf(cli_error_message, sizeof(cli_error_message) - 1,
135                                         "Out of memory");
136                                 break;
137                         default:
138                                 slprintf(cli_error_message, sizeof(cli_error_message) - 1,
139                                         "Unknown error code %d\n", cli->smb_rw_error );
140                                 break;
141                 }
142                 goto done;
143         }
144
145         /* Case #1: RAP error */
146         if (cli->rap_error) {
147                 for (i = 0; rap_errmap[i].message != NULL; i++) {
148                         if (rap_errmap[i].err == cli->rap_error) {
149                                 return rap_errmap[i].message;
150                         }
151                 }
152
153                 slprintf(cli_error_message, sizeof(cli_error_message) - 1, "RAP code %d",
154                         cli->rap_error);
155
156                 goto done;
157         }
158
159         /* Case #2: 32-bit NT errors */
160         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
161                 NTSTATUS status = NT_STATUS(IVAL(cli->inbuf,smb_rcls));
162
163                 return nt_errstr(status);
164         }
165
166         cli_dos_error(cli, &errclass, &errnum);
167
168         /* Case #3: SMB error */
169
170         return cli_smb_errstr(cli);
171
172  done:
173         result = talloc_strdup(talloc_tos(), cli_error_message);
174         SMB_ASSERT(result);
175         return result;
176 }
177
178
179 /****************************************************************************
180  Return the 32-bit NT status code from the last packet.
181 ****************************************************************************/
182
183 NTSTATUS cli_nt_error(struct cli_state *cli)
184 {
185         int flgs2 = SVAL(cli->inbuf,smb_flg2);
186
187         /* Deal with socket errors first. */
188         if (cli->fd == -1 && cli->smb_rw_error) {
189                 return cli_smb_rw_error_to_ntstatus(cli);
190         }
191
192         if (!(flgs2 & FLAGS2_32_BIT_ERROR_CODES)) {
193                 int e_class  = CVAL(cli->inbuf,smb_rcls);
194                 int code  = SVAL(cli->inbuf,smb_err);
195                 return dos_to_ntstatus(e_class, code);
196         }
197
198         return NT_STATUS(IVAL(cli->inbuf,smb_rcls));
199 }
200
201
202 /****************************************************************************
203  Return the DOS error from the last packet - an error class and an error
204  code.
205 ****************************************************************************/
206
207 void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode)
208 {
209         int  flgs2;
210
211         if(!cli->initialised) {
212                 return;
213         }
214
215         /* Deal with socket errors first. */
216         if (cli->fd == -1 && cli->smb_rw_error) {
217                 NTSTATUS status = cli_smb_rw_error_to_ntstatus(cli);
218                 ntstatus_to_dos( status, eclass, ecode);
219                 return;
220         }
221
222         flgs2 = SVAL(cli->inbuf,smb_flg2);
223
224         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
225                 NTSTATUS ntstatus = NT_STATUS(IVAL(cli->inbuf, smb_rcls));
226                 ntstatus_to_dos(ntstatus, eclass, ecode);
227                 return;
228         }
229
230         *eclass  = CVAL(cli->inbuf,smb_rcls);
231         *ecode  = SVAL(cli->inbuf,smb_err);
232 }
233
234
235 /* Return a UNIX errno appropriate for the error received in the last
236    packet. */
237
238 int cli_errno(struct cli_state *cli)
239 {
240         NTSTATUS status;
241
242         if (cli_is_nt_error(cli)) {
243                 status = cli_nt_error(cli);
244                 return map_errno_from_nt_status(status);
245         }
246
247         if (cli_is_dos_error(cli)) {
248                 uint8 eclass;
249                 uint32 ecode;
250
251                 cli_dos_error(cli, &eclass, &ecode);
252                 status = dos_to_ntstatus(eclass, ecode);
253                 return map_errno_from_nt_status(status);
254         }
255
256         /*
257          * Yuck!  A special case for this Vista error.  Since its high-order
258          * byte isn't 0xc0, it doesn't match cli_is_nt_error() above.
259          */
260         status = cli_nt_error(cli);
261         if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
262             return EACCES;
263         }
264
265         /* for other cases */
266         return EINVAL;
267 }
268
269 /* Return true if the last packet was in error */
270
271 bool cli_is_error(struct cli_state *cli)
272 {
273         uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), rcls = 0;
274
275         /* A socket error is always an error. */
276         if (cli->fd == -1 && cli->smb_rw_error != 0) {
277                 return True;
278         }
279
280         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
281                 /* Return error is error bits are set */
282                 rcls = IVAL(cli->inbuf, smb_rcls);
283                 return (rcls & 0xF0000000) == 0xC0000000;
284         }
285
286         /* Return error if error class in non-zero */
287
288         rcls = CVAL(cli->inbuf, smb_rcls);
289         return rcls != 0;
290 }
291
292 /* Return true if the last error was an NT error */
293
294 bool cli_is_nt_error(struct cli_state *cli)
295 {
296         uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
297
298         /* A socket error is always an NT error. */
299         if (cli->fd == -1 && cli->smb_rw_error != 0) {
300                 return True;
301         }
302
303         return cli_is_error(cli) && (flgs2 & FLAGS2_32_BIT_ERROR_CODES);
304 }
305
306 /* Return true if the last error was a DOS error */
307
308 bool cli_is_dos_error(struct cli_state *cli)
309 {
310         uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
311
312         /* A socket error is always a DOS error. */
313         if (cli->fd == -1 && cli->smb_rw_error != 0) {
314                 return True;
315         }
316
317         return cli_is_error(cli) && !(flgs2 & FLAGS2_32_BIT_ERROR_CODES);
318 }
319
320 bool cli_state_is_connected(struct cli_state *cli)
321 {
322         if (cli == NULL) {
323                 return false;
324         }
325
326         if (!cli->initialised) {
327                 return false;
328         }
329
330         if (cli->fd == -1) {
331                 return false;
332         }
333
334         return true;
335 }
336