/src/samba/libcli/util/nterr.c
Line | Count | Source |
1 | | /* |
2 | | * Unix SMB/CIFS implementation. |
3 | | * RPC Pipe client / server routines |
4 | | * |
5 | | * Copyright (C) Luke Kenneth Casson Leighton 1997-2001. |
6 | | * Copyright (C) Andrew Bartlett |
7 | | * Copyright (C) Andrew Tridgell |
8 | | * |
9 | | * This program is free software; you can redistribute it and/or modify |
10 | | * it under the terms of the GNU General Public License as published by |
11 | | * the Free Software Foundation; either version 3 of the License, or |
12 | | * (at your option) any later version. |
13 | | * |
14 | | * This program is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU General Public License |
20 | | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | /* NT error codes. please read nterr.h */ |
24 | | |
25 | | #include "includes.h" |
26 | | #include "../libcli/ldap/ldap_errors.h" |
27 | | #undef strcasecmp |
28 | | |
29 | | #if !defined(N_) |
30 | | #define N_(string) string |
31 | | #endif |
32 | | |
33 | | #define DOS_CODE(class, code) { #class ":" #code, NT_STATUS_DOS(class, code) } |
34 | | #define LDAP_CODE(code) { #code, NT_STATUS_LDAP(code) } |
35 | | |
36 | | typedef struct |
37 | | { |
38 | | const char *nt_errstr; |
39 | | NTSTATUS nt_errcode; |
40 | | } nt_err_code_struct; |
41 | | |
42 | | #include "nterr_gen.c" |
43 | | |
44 | | /* Errors which aren't in the generated code because they're not in the |
45 | | * same table as the other ones. */ |
46 | | static const nt_err_code_struct special_errs[] = |
47 | | { |
48 | | { "STATUS_NO_MORE_FILES", STATUS_NO_MORE_FILES }, |
49 | | { "STATUS_INVALID_EA_NAME", STATUS_INVALID_EA_NAME }, |
50 | | { "STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW }, |
51 | | { "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES }, |
52 | | { "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED }, |
53 | | { "NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS", NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS }, |
54 | | { "NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION", NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION }, |
55 | | { "NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP", NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP }, |
56 | | { "NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT }, |
57 | | { "NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST }, |
58 | | { "NT_STATUS_ABIOS_LID_ALREADY_OWNED", NT_STATUS_ABIOS_LID_ALREADY_OWNED }, |
59 | | { "NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER }, |
60 | | { "NT_STATUS_ABIOS_INVALID_COMMAND", NT_STATUS_ABIOS_INVALID_COMMAND }, |
61 | | { "NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID }, |
62 | | { "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE }, |
63 | | { "NT_STATUS_ABIOS_INVALID_SELECTOR", NT_STATUS_ABIOS_INVALID_SELECTOR }, |
64 | | { "NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE }, |
65 | | { "NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE }, |
66 | | { "NT_STATUS_VHD_SHARED", NT_STATUS_VHD_SHARED }, |
67 | | { "NT_STATUS_SMB_BAD_CLUSTER_DIALECT", NT_STATUS_SMB_BAD_CLUSTER_DIALECT }, |
68 | | { "NT_STATUS_NO_SUCH_JOB", NT_STATUS_NO_SUCH_JOB }, |
69 | | |
70 | | DOS_CODE(ERRDOS, ERRsuccess), |
71 | | DOS_CODE(ERRDOS, ERRbadfunc), |
72 | | DOS_CODE(ERRDOS, ERRbadfile), |
73 | | DOS_CODE(ERRDOS, ERRbadpath), |
74 | | DOS_CODE(ERRDOS, ERRnofids), |
75 | | DOS_CODE(ERRDOS, ERRnoaccess), |
76 | | DOS_CODE(ERRDOS, ERRbadfid), |
77 | | DOS_CODE(ERRDOS, ERRbadmcb), |
78 | | DOS_CODE(ERRDOS, ERRnomem), |
79 | | DOS_CODE(ERRDOS, ERRbadmem), |
80 | | DOS_CODE(ERRDOS, ERRbadenv), |
81 | | DOS_CODE(ERRDOS, ERRbadaccess), |
82 | | DOS_CODE(ERRDOS, ERRbaddata), |
83 | | DOS_CODE(ERRDOS, ERRres), |
84 | | DOS_CODE(ERRDOS, ERRbaddrive), |
85 | | DOS_CODE(ERRDOS, ERRremcd), |
86 | | DOS_CODE(ERRDOS, ERRdiffdevice), |
87 | | DOS_CODE(ERRDOS, ERRnofiles), |
88 | | DOS_CODE(ERRDOS, ERRgeneral), |
89 | | DOS_CODE(ERRDOS, ERRbadshare), |
90 | | DOS_CODE(ERRDOS, ERRlock), |
91 | | DOS_CODE(ERRDOS, ERRunsup), |
92 | | DOS_CODE(ERRDOS, ERRnetnamedel), |
93 | | DOS_CODE(ERRDOS, ERRnosuchshare), |
94 | | DOS_CODE(ERRDOS, ERRfilexists), |
95 | | DOS_CODE(ERRDOS, ERRinvalidparam), |
96 | | DOS_CODE(ERRDOS, ERRcannotopen), |
97 | | DOS_CODE(ERRDOS, ERRinsufficientbuffer), |
98 | | DOS_CODE(ERRDOS, ERRinvalidname), |
99 | | DOS_CODE(ERRDOS, ERRunknownlevel), |
100 | | DOS_CODE(ERRDOS, ERRnotlocked), |
101 | | DOS_CODE(ERRDOS, ERRinvalidpath), |
102 | | DOS_CODE(ERRDOS, ERRcancelviolation), |
103 | | DOS_CODE(ERRDOS, ERRnoatomiclocks), |
104 | | DOS_CODE(ERRDOS, ERRrename), |
105 | | DOS_CODE(ERRDOS, ERRbadpipe), |
106 | | DOS_CODE(ERRDOS, ERRpipebusy), |
107 | | DOS_CODE(ERRDOS, ERRpipeclosing), |
108 | | DOS_CODE(ERRDOS, ERRnotconnected), |
109 | | DOS_CODE(ERRDOS, ERRmoredata), |
110 | | DOS_CODE(ERRDOS, ERRnomoreitems), |
111 | | DOS_CODE(ERRDOS, ERRbaddirectory), |
112 | | DOS_CODE(ERRDOS, ERReasnotsupported), |
113 | | DOS_CODE(ERRDOS, ERRlogonfailure), |
114 | | DOS_CODE(ERRDOS, ERRbuftoosmall), |
115 | | DOS_CODE(ERRDOS, ERRunknownipc), |
116 | | DOS_CODE(ERRDOS, ERRnosuchprintjob), |
117 | | DOS_CODE(ERRDOS, ERRinvgroup), |
118 | | DOS_CODE(ERRDOS, ERRnoipc), |
119 | | DOS_CODE(ERRDOS, ERRdriveralreadyinstalled), |
120 | | DOS_CODE(ERRDOS, ERRunknownprinterport), |
121 | | DOS_CODE(ERRDOS, ERRunknownprinterdriver), |
122 | | DOS_CODE(ERRDOS, ERRunknownprintprocessor), |
123 | | DOS_CODE(ERRDOS, ERRinvalidseparatorfile), |
124 | | DOS_CODE(ERRDOS, ERRinvalidjobpriority), |
125 | | DOS_CODE(ERRDOS, ERRinvalidprintername), |
126 | | DOS_CODE(ERRDOS, ERRprinteralreadyexists), |
127 | | DOS_CODE(ERRDOS, ERRinvalidprintercommand), |
128 | | DOS_CODE(ERRDOS, ERRinvaliddatatype), |
129 | | DOS_CODE(ERRDOS, ERRinvalidenvironment), |
130 | | DOS_CODE(ERRDOS, ERRunknownprintmonitor), |
131 | | DOS_CODE(ERRDOS, ERRprinterdriverinuse), |
132 | | DOS_CODE(ERRDOS, ERRspoolfilenotfound), |
133 | | DOS_CODE(ERRDOS, ERRnostartdoc), |
134 | | DOS_CODE(ERRDOS, ERRnoaddjob), |
135 | | DOS_CODE(ERRDOS, ERRprintprocessoralreadyinstalled), |
136 | | DOS_CODE(ERRDOS, ERRprintmonitoralreadyinstalled), |
137 | | DOS_CODE(ERRDOS, ERRinvalidprintmonitor), |
138 | | DOS_CODE(ERRDOS, ERRprintmonitorinuse), |
139 | | DOS_CODE(ERRDOS, ERRprinterhasjobsqueued), |
140 | | DOS_CODE(ERRDOS, ERReainconsistent), |
141 | | |
142 | | DOS_CODE(ERRSRV, ERRerror), |
143 | | DOS_CODE(ERRSRV, ERRbadpw), |
144 | | DOS_CODE(ERRSRV, ERRbadtype), |
145 | | DOS_CODE(ERRSRV, ERRaccess), |
146 | | DOS_CODE(ERRSRV, ERRinvnid), |
147 | | DOS_CODE(ERRSRV, ERRinvnetname), |
148 | | DOS_CODE(ERRSRV, ERRinvdevice), |
149 | | DOS_CODE(ERRSRV, ERRqfull), |
150 | | DOS_CODE(ERRSRV, ERRqtoobig), |
151 | | DOS_CODE(ERRSRV, ERRinvpfid), |
152 | | DOS_CODE(ERRSRV, ERRsmbcmd), |
153 | | DOS_CODE(ERRSRV, ERRsrverror), |
154 | | DOS_CODE(ERRSRV, ERRfilespecs), |
155 | | DOS_CODE(ERRSRV, ERRbadlink), |
156 | | DOS_CODE(ERRSRV, ERRbadpermits), |
157 | | DOS_CODE(ERRSRV, ERRbadpid), |
158 | | DOS_CODE(ERRSRV, ERRsetattrmode), |
159 | | DOS_CODE(ERRSRV, ERRpaused), |
160 | | DOS_CODE(ERRSRV, ERRmsgoff), |
161 | | DOS_CODE(ERRSRV, ERRnoroom), |
162 | | DOS_CODE(ERRSRV, ERRrmuns), |
163 | | DOS_CODE(ERRSRV, ERRtimeout), |
164 | | DOS_CODE(ERRSRV, ERRnoresource), |
165 | | DOS_CODE(ERRSRV, ERRtoomanyuids), |
166 | | DOS_CODE(ERRSRV, ERRbaduid), |
167 | | DOS_CODE(ERRSRV, ERRuseMPX), |
168 | | DOS_CODE(ERRSRV, ERRuseSTD), |
169 | | DOS_CODE(ERRSRV, ERRcontMPX), |
170 | | DOS_CODE(ERRSRV, ERRnosupport), |
171 | | DOS_CODE(ERRSRV, ERRunknownsmb), |
172 | | |
173 | | DOS_CODE(ERRHRD, ERRnowrite), |
174 | | DOS_CODE(ERRHRD, ERRbadunit), |
175 | | DOS_CODE(ERRHRD, ERRnotready), |
176 | | DOS_CODE(ERRHRD, ERRbadcmd), |
177 | | DOS_CODE(ERRHRD, ERRdata), |
178 | | DOS_CODE(ERRHRD, ERRbadreq), |
179 | | DOS_CODE(ERRHRD, ERRseek), |
180 | | DOS_CODE(ERRHRD, ERRbadmedia), |
181 | | DOS_CODE(ERRHRD, ERRbadsector), |
182 | | DOS_CODE(ERRHRD, ERRnopaper), |
183 | | DOS_CODE(ERRHRD, ERRwrite), |
184 | | DOS_CODE(ERRHRD, ERRread), |
185 | | DOS_CODE(ERRHRD, ERRgeneral), |
186 | | DOS_CODE(ERRHRD, ERRwrongdisk), |
187 | | DOS_CODE(ERRHRD, ERRFCBunavail), |
188 | | DOS_CODE(ERRHRD, ERRsharebufexc), |
189 | | DOS_CODE(ERRHRD, ERRdiskfull), |
190 | | |
191 | | LDAP_CODE(LDAP_SUCCESS), |
192 | | LDAP_CODE(LDAP_OPERATIONS_ERROR), |
193 | | LDAP_CODE(LDAP_PROTOCOL_ERROR), |
194 | | LDAP_CODE(LDAP_TIME_LIMIT_EXCEEDED), |
195 | | LDAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED), |
196 | | LDAP_CODE(LDAP_COMPARE_FALSE), |
197 | | LDAP_CODE(LDAP_COMPARE_TRUE), |
198 | | LDAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED), |
199 | | LDAP_CODE(LDAP_STRONG_AUTH_REQUIRED), |
200 | | LDAP_CODE(LDAP_REFERRAL), |
201 | | LDAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED), |
202 | | LDAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION), |
203 | | LDAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED), |
204 | | LDAP_CODE(LDAP_SASL_BIND_IN_PROGRESS), |
205 | | LDAP_CODE(LDAP_NO_SUCH_ATTRIBUTE), |
206 | | LDAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE), |
207 | | LDAP_CODE(LDAP_INAPPROPRIATE_MATCHING), |
208 | | LDAP_CODE(LDAP_CONSTRAINT_VIOLATION), |
209 | | LDAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS), |
210 | | LDAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX), |
211 | | LDAP_CODE(LDAP_NO_SUCH_OBJECT), |
212 | | LDAP_CODE(LDAP_ALIAS_PROBLEM), |
213 | | LDAP_CODE(LDAP_INVALID_DN_SYNTAX), |
214 | | LDAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM), |
215 | | LDAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION), |
216 | | LDAP_CODE(LDAP_INVALID_CREDENTIALS), |
217 | | LDAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS), |
218 | | LDAP_CODE(LDAP_BUSY), |
219 | | LDAP_CODE(LDAP_UNAVAILABLE), |
220 | | LDAP_CODE(LDAP_UNWILLING_TO_PERFORM), |
221 | | LDAP_CODE(LDAP_LOOP_DETECT), |
222 | | LDAP_CODE(LDAP_NAMING_VIOLATION), |
223 | | LDAP_CODE(LDAP_OBJECT_CLASS_VIOLATION), |
224 | | LDAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF), |
225 | | LDAP_CODE(LDAP_NOT_ALLOWED_ON_RDN), |
226 | | LDAP_CODE(LDAP_ENTRY_ALREADY_EXISTS), |
227 | | LDAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED), |
228 | | LDAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS), |
229 | | LDAP_CODE(LDAP_OTHER), |
230 | | |
231 | | { NULL, NT_STATUS(0) } |
232 | | }; |
233 | | |
234 | | /***************************************************************************** |
235 | | Returns an NT_STATUS constant as a string for inclusion in autogen C code. |
236 | | *****************************************************************************/ |
237 | | |
238 | | const char *get_nt_error_c_code(TALLOC_CTX *mem_ctx, NTSTATUS nt_code) |
239 | 0 | { |
240 | 0 | char *result; |
241 | 0 | int idx = 0; |
242 | |
|
243 | 0 | while (special_errs[idx].nt_errstr != NULL) { |
244 | 0 | if (NT_STATUS_V(special_errs[idx].nt_errcode) == |
245 | 0 | NT_STATUS_V(nt_code)) { |
246 | 0 | result = talloc_strdup(mem_ctx, special_errs[idx].nt_errstr); |
247 | 0 | return result; |
248 | 0 | } |
249 | 0 | idx++; |
250 | 0 | } |
251 | | |
252 | 0 | idx = 0; |
253 | |
|
254 | 0 | while (nt_errs[idx].nt_errstr != NULL) { |
255 | 0 | if (NT_STATUS_V(nt_errs[idx].nt_errcode) == |
256 | 0 | NT_STATUS_V(nt_code)) { |
257 | 0 | result = talloc_strdup(mem_ctx, nt_errs[idx].nt_errstr); |
258 | 0 | return result; |
259 | 0 | } |
260 | 0 | idx++; |
261 | 0 | } |
262 | | |
263 | 0 | result = talloc_asprintf(mem_ctx, "NT_STATUS(0x%08x)", |
264 | 0 | NT_STATUS_V(nt_code)); |
265 | 0 | return result; |
266 | 0 | } |
267 | | |
268 | | /***************************************************************************** |
269 | | Returns the NT_STATUS constant matching the string supplied (as an NTSTATUS) |
270 | | *****************************************************************************/ |
271 | | |
272 | | NTSTATUS nt_status_string_to_code(const char *nt_status_str) |
273 | 0 | { |
274 | 0 | int idx = 0; |
275 | |
|
276 | 0 | while (special_errs[idx].nt_errstr != NULL) { |
277 | 0 | if (strcasecmp(special_errs[idx].nt_errstr, nt_status_str) == 0) { |
278 | 0 | return special_errs[idx].nt_errcode; |
279 | 0 | } |
280 | 0 | idx++; |
281 | 0 | } |
282 | | |
283 | 0 | idx = 0; |
284 | |
|
285 | 0 | while (nt_errs[idx].nt_errstr != NULL) { |
286 | 0 | if (strcasecmp(nt_errs[idx].nt_errstr, nt_status_str) == 0) { |
287 | 0 | return nt_errs[idx].nt_errcode; |
288 | 0 | } |
289 | 0 | idx++; |
290 | 0 | } |
291 | | |
292 | 0 | return NT_STATUS_UNSUCCESSFUL; |
293 | 0 | } |
294 | | |
295 | | /** |
296 | | * Squash an NT_STATUS in line with security requirements. |
297 | | * In an attempt to avoid giving the whole game away when users |
298 | | * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and |
299 | | * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations |
300 | | * (session setups in particular). |
301 | | * |
302 | | * @param nt_status NTSTATUS input for squashing. |
303 | | * @return the 'squashed' nt_status |
304 | | **/ |
305 | | |
306 | | NTSTATUS nt_status_squash(NTSTATUS nt_status) |
307 | 0 | { |
308 | 0 | if NT_STATUS_IS_OK(nt_status) { |
309 | 0 | return nt_status; |
310 | 0 | } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { |
311 | | /* Match WinXP and don't give the game away */ |
312 | 0 | return NT_STATUS_LOGON_FAILURE; |
313 | |
|
314 | 0 | } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { |
315 | | /* Match WinXP and don't give the game away */ |
316 | 0 | return NT_STATUS_LOGON_FAILURE; |
317 | 0 | } else { |
318 | 0 | return nt_status; |
319 | 0 | } |
320 | 0 | } |
321 | | |
322 | | /***************************************************************************** |
323 | | Returns an NT error message. not amazingly helpful, but better than a number. |
324 | | *****************************************************************************/ |
325 | | |
326 | | const char *nt_errstr(NTSTATUS nt_code) |
327 | 289k | { |
328 | 289k | static char msg[20]; |
329 | 289k | int idx = 0; |
330 | | |
331 | 51.0M | while (special_errs[idx].nt_errstr != NULL) { |
332 | 50.7M | if (NT_STATUS_V(special_errs[idx].nt_errcode) == |
333 | 50.7M | NT_STATUS_V(nt_code)) { |
334 | 4.53k | return special_errs[idx].nt_errstr; |
335 | 4.53k | } |
336 | 50.7M | idx++; |
337 | 50.7M | } |
338 | | |
339 | 285k | idx = 0; |
340 | | |
341 | 501M | while (nt_errs[idx].nt_errstr != NULL) { |
342 | 501M | if (NT_STATUS_V(nt_errs[idx].nt_errcode) == |
343 | 501M | NT_STATUS_V(nt_code)) { |
344 | 5.94k | return nt_errs[idx].nt_errstr; |
345 | 5.94k | } |
346 | 501M | idx++; |
347 | 501M | } |
348 | | |
349 | | /* |
350 | | * NTSTATUS codes have 0xC000 in the upper 16-bit, if the |
351 | | * upper 16-bit are not 0 and not 0xC000, it's likely |
352 | | * an HRESULT. |
353 | | * |
354 | | * E.g. we should display HRES_SEC_E_WRONG_PRINCIPAL instead of |
355 | | * 'NT code 0x80090322' |
356 | | */ |
357 | 279k | if ((NT_STATUS_V(nt_code) & 0xFFFF0000) != 0 && |
358 | 275k | (NT_STATUS_V(nt_code) & 0xFFFF0000) != 0xC0000000) |
359 | 275k | { |
360 | 275k | HRESULT hres = HRES_ERROR(NT_STATUS_V(nt_code)); |
361 | 275k | return hresult_errstr(hres); |
362 | 275k | } |
363 | | |
364 | | /* |
365 | | * This should not really happen, we should have all error codes |
366 | | * available. We have a problem that this might get wrongly |
367 | | * overwritten by later calls in the same DEBUG statement. |
368 | | */ |
369 | | |
370 | 279k | snprintf(msg, sizeof(msg), "NT code 0x%08x", NT_STATUS_V(nt_code)); |
371 | 3.61k | return msg; |
372 | 279k | } |
373 | | |
374 | | /************************************************************************ |
375 | | Print friendlier version of NT error code |
376 | | ***********************************************************************/ |
377 | | |
378 | | const char *get_friendly_nt_error_msg(NTSTATUS nt_code) |
379 | 0 | { |
380 | 0 | int idx = 0; |
381 | |
|
382 | 0 | while (nt_err_desc[idx].nt_errstr != NULL) { |
383 | 0 | if (NT_STATUS_V(nt_err_desc[idx].nt_errcode) == NT_STATUS_V(nt_code)) { |
384 | 0 | return nt_err_desc[idx].nt_errstr; |
385 | 0 | } |
386 | 0 | idx++; |
387 | 0 | } |
388 | | |
389 | | /* fall back to NT_STATUS_XXX string */ |
390 | | |
391 | 0 | return nt_errstr(nt_code); |
392 | 0 | } |