root/source3/libsmb/clierror.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cli_smb_errstr
  2. cli_smb_rw_error_to_ntstatus
  3. cli_errstr
  4. cli_nt_error
  5. cli_dos_error
  6. cli_errno
  7. cli_is_error
  8. cli_is_nt_error
  9. cli_is_dos_error
  10. cli_get_nt_error
  11. cli_set_nt_error
  12. cli_reset_error

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

/* [<][>][^][v][top][bottom][index][help] */