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 #include "../libcli/smb/smbXcli_base.h"
25 
26 /***************************************************************************
27  Return an error message - either an NT error, SMB error or a RAP error.
28  Note some of the NT errors are actually warnings or "informational" errors
29  in which case they can be safely ignored.
30 ****************************************************************************/
31 
cli_errstr(struct cli_state * cli)32 const char *cli_errstr(struct cli_state *cli)
33 {
34 	fstring cli_error_message;
35 	char *result;
36 
37 	if (!cli->initialised) {
38 		fstrcpy(cli_error_message, "[Programmer's error] cli_errstr called on uninitialized cli_stat struct!\n");
39 		goto done;
40 	}
41 
42 	/* Case #1: RAP error */
43 	if (cli->rap_error) {
44 		strlcpy(cli_error_message, win_errstr(W_ERROR(cli->rap_error)),
45 			sizeof(cli_error_message));
46 		goto done;
47 	}
48 
49 	if (!cli_state_is_connected(cli) && NT_STATUS_IS_OK(cli->raw_status)) {
50 		return nt_errstr(NT_STATUS_CONNECTION_DISCONNECTED);
51 	}
52 
53 	return nt_errstr(cli->raw_status);
54  done:
55 	result = talloc_strdup(talloc_tos(), cli_error_message);
56 	SMB_ASSERT(result);
57 	return result;
58 }
59 
60 
61 /****************************************************************************
62  Return the 32-bit NT status code from the last packet.
63 ****************************************************************************/
64 
cli_nt_error(struct cli_state * cli)65 NTSTATUS cli_nt_error(struct cli_state *cli)
66 {
67 	/* Deal with socket errors first. */
68 	if (!cli_state_is_connected(cli)) {
69 		return NT_STATUS_CONNECTION_DISCONNECTED;
70 	}
71 
72 	if (NT_STATUS_IS_DOS(cli->raw_status)) {
73 		int e_class = NT_STATUS_DOS_CLASS(cli->raw_status);
74 		int code = NT_STATUS_DOS_CODE(cli->raw_status);
75 		return dos_to_ntstatus(e_class, code);
76 	}
77 
78 	return cli->raw_status;
79 }
80 
81 
82 /****************************************************************************
83  Return the DOS error from the last packet - an error class and an error
84  code.
85 ****************************************************************************/
86 
cli_dos_error(struct cli_state * cli,uint8_t * eclass,uint32_t * ecode)87 void cli_dos_error(struct cli_state *cli, uint8_t *eclass, uint32_t *ecode)
88 {
89 	if (!cli_state_is_connected(cli)) {
90 		*eclass = ERRDOS;
91 		*ecode = ERRnotconnected;
92 		return;
93 	}
94 
95 	if (!NT_STATUS_IS_DOS(cli->raw_status)) {
96 		ntstatus_to_dos(cli->raw_status, eclass, ecode);
97 		return;
98 	}
99 
100 	*eclass = NT_STATUS_DOS_CLASS(cli->raw_status);
101 	*ecode = NT_STATUS_DOS_CODE(cli->raw_status);
102 }
103 
104 
105 /* Return a UNIX errno appropriate for the error received in the last
106    packet. */
107 
cli_errno(struct cli_state * cli)108 int cli_errno(struct cli_state *cli)
109 {
110 	NTSTATUS status;
111 
112 	if (cli_is_nt_error(cli)) {
113 		status = cli_nt_error(cli);
114 		return map_errno_from_nt_status(status);
115 	}
116 
117         if (cli_is_dos_error(cli)) {
118                 uint8_t eclass;
119                 uint32_t ecode;
120 
121                 cli_dos_error(cli, &eclass, &ecode);
122 		status = dos_to_ntstatus(eclass, ecode);
123 		return map_errno_from_nt_status(status);
124         }
125 
126         /*
127          * Yuck!  A special case for this Vista error.  Since its high-order
128          * byte isn't 0xc0, it doesn't match cli_is_nt_error() above.
129          */
130         status = cli_nt_error(cli);
131         if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
132             return EACCES;
133         }
134 
135 	/* for other cases */
136 	return EINVAL;
137 }
138 
139 /* Return true if the last packet was in error */
140 
cli_is_error(struct cli_state * cli)141 bool cli_is_error(struct cli_state *cli)
142 {
143 	/* A socket error is always an error. */
144 	if (!cli_state_is_connected(cli)) {
145 		return true;
146 	}
147 
148 	if (NT_STATUS_IS_DOS(cli->raw_status)) {
149 		/* Return error if error class in non-zero */
150 		uint8_t rcls = NT_STATUS_DOS_CLASS(cli->raw_status);
151 		return rcls != 0;
152 	}
153 
154 	return NT_STATUS_IS_ERR(cli->raw_status);
155 }
156 
157 /* Return true if the last error was an NT error */
158 
cli_is_nt_error(struct cli_state * cli)159 bool cli_is_nt_error(struct cli_state *cli)
160 {
161 	/* A socket error is always an NT error. */
162 	if (!cli_state_is_connected(cli)) {
163 		return true;
164 	}
165 
166 	return cli_is_error(cli) && !NT_STATUS_IS_DOS(cli->raw_status);
167 }
168 
169 /* Return true if the last error was a DOS error */
170 
cli_is_dos_error(struct cli_state * cli)171 bool cli_is_dos_error(struct cli_state *cli)
172 {
173 	/* A socket error is always a DOS error. */
174 	if (!cli_state_is_connected(cli)) {
175 		return true;
176 	}
177 
178 	return cli_is_error(cli) && NT_STATUS_IS_DOS(cli->raw_status);
179 }
180 
cli_state_is_connected(struct cli_state * cli)181 bool cli_state_is_connected(struct cli_state *cli)
182 {
183 	if (cli == NULL) {
184 		return false;
185 	}
186 
187 	if (!cli->initialised) {
188 		return false;
189 	}
190 
191 	return smbXcli_conn_is_connected(cli->conn);
192 }
193