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