]>
Commit | Line | Data |
---|---|---|
04e4e140 | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors |
04e4e140 AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
94439e4e | 8 | |
7c16470c | 9 | /* UNIX SMBlib NetBIOS implementation |
94439e4e | 10 | |
7c16470c AJ |
11 | Version 1.0 |
12 | SMBlib Utility Routines | |
a19a836d | 13 | |
7c16470c | 14 | Copyright (C) Richard Sharpe 1996 |
7c16470c AJ |
15 | */ |
16 | ||
17 | /* | |
18 | This program is free software; you can redistribute it and/or modify | |
19 | it under the terms of the GNU General Public License as published by | |
20 | the Free Software Foundation; either version 2 of the License, or | |
21 | (at your option) any later version. | |
22 | ||
23 | This program is distributed in the hope that it will be useful, | |
24 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
26 | GNU General Public License for more details. | |
27 | ||
28 | You should have received a copy of the GNU General Public License | |
29 | along with this program; if not, write to the Free Software | |
30 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
31 | */ | |
32 | ||
04e4e140 | 33 | #include "squid.h" |
7c16470c | 34 | #include "rfcnb/rfcnb.h" |
602d9612 A |
35 | #include "smblib/smblib-priv.h" |
36 | #include "smblib/smblib.h" | |
7c16470c AJ |
37 | |
38 | #if HAVE_STRING_H | |
39 | #include <string.h> | |
40 | #endif | |
94439e4e | 41 | |
eb3ffa70 AJ |
42 | int SMB_Types[] = {SMB_P_Core, |
43 | SMB_P_CorePlus, | |
44 | SMB_P_DOSLanMan1, | |
45 | SMB_P_DOSLanMan1, | |
46 | SMB_P_LanMan1, | |
47 | SMB_P_DOSLanMan2, | |
48 | SMB_P_LanMan2, | |
49 | SMB_P_LanMan2_1, | |
50 | SMB_P_LanMan2_1, | |
51 | SMB_P_NT1, | |
52 | SMB_P_NT1, | |
53 | SMB_P_NT1, | |
54 | -1 | |
55 | }; | |
26ac0430 | 56 | |
20a423f3 | 57 | #if UNDEFINED |
7c16470c AJ |
58 | char *SMB_DOSTimToStr(int DOS_time); |
59 | char *SMB_AtrToStr(int attribs, BOOL verbose); | |
60 | int SMB_Get_Tree_MBS(SMB_Tree_Handle tree); | |
61 | int SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle); | |
62 | int SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle); | |
20a423f3 | 63 | #endif /* UNDEFINED */ |
7c16470c AJ |
64 | int SMB_Get_Protocol(SMB_Handle_Type Con_Handle); |
65 | int SMB_Figure_Protocol(const char *dialects[], int prot_index); | |
66 | int SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard); | |
94439e4e | 67 | |
7c16470c | 68 | #if UNDEFINED |
94439e4e | 69 | /* Print out an SMB pkt in all its gory detail ... */ |
7c16470c AJ |
70 | |
71 | void SMB_Print_Pkt(FILE fd, RFCNB_Pkt *pkt, BOOL command, int Offset, int Len) | |
72 | ||
94439e4e | 73 | { |
74 | ||
75 | /* Well, just how do we do this ... print it I suppose */ | |
76 | ||
77 | /* Print out the SMB header ... */ | |
78 | ||
79 | /* Print the command */ | |
80 | ||
81 | /* Print the other bits in the header */ | |
82 | ||
94439e4e | 83 | /* etc */ |
84 | ||
85 | } | |
7c16470c | 86 | #endif |
94439e4e | 87 | |
88 | /* Convert a DOS Date_Time to a local host type date time for printing */ | |
89 | ||
20a423f3 | 90 | #if UNDEFINED |
7c16470c AJ |
91 | char *SMB_DOSTimToStr(int DOS_time) |
92 | ||
94439e4e | 93 | { |
94 | static char SMB_Time_Temp[48]; | |
95 | int DOS_sec, DOS_min, DOS_hour, DOS_day, DOS_month, DOS_year; | |
96 | ||
97 | SMB_Time_Temp[0] = 0; | |
98 | ||
7c16470c AJ |
99 | DOS_sec = (DOS_time & 0x001F) * 2; |
100 | DOS_min = (DOS_time & 0x07E0) >> 5; | |
101 | DOS_hour = ((DOS_time & 0xF800) >> 11); | |
94439e4e | 102 | |
7c16470c | 103 | DOS_day = (DOS_time & 0x001F0000) >> 16; |
94439e4e | 104 | DOS_month = (DOS_time & 0x01E00000) >> 21; |
7c16470c | 105 | DOS_year = ((DOS_time & 0xFE000000) >> 25) + 80; |
94439e4e | 106 | |
dc47f531 | 107 | snprintf(SMB_Time_Temp, 48, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month, |
3c96dd46 | 108 | DOS_year, DOS_hour, DOS_min, DOS_sec); |
94439e4e | 109 | |
7c16470c | 110 | return(SMB_Time_Temp); |
94439e4e | 111 | |
112 | } | |
113 | ||
7c16470c AJ |
114 | /* Convert an attribute byte/word etc to a string ... We return a pointer |
115 | to a static string which we guarantee is long enough. If verbose is | |
116 | true, we print out long form of strings ... */ | |
117 | ||
118 | char *SMB_AtrToStr(int attribs, BOOL verbose) | |
119 | ||
94439e4e | 120 | { |
121 | static char SMB_Attrib_Temp[128]; | |
122 | ||
123 | SMB_Attrib_Temp[0] = 0; | |
124 | ||
125 | if (attribs & SMB_FA_ROF) | |
7c16470c | 126 | strcat(SMB_Attrib_Temp, (verbose?"Read Only ":"R")); |
94439e4e | 127 | |
128 | if (attribs & SMB_FA_HID) | |
7c16470c | 129 | strcat(SMB_Attrib_Temp, (verbose?"Hidden ":"H")); |
94439e4e | 130 | |
131 | if (attribs & SMB_FA_SYS) | |
7c16470c | 132 | strcat(SMB_Attrib_Temp, (verbose?"System ":"S")); |
94439e4e | 133 | |
134 | if (attribs & SMB_FA_VOL) | |
7c16470c | 135 | strcat(SMB_Attrib_Temp, (verbose?"Volume ":"V")); |
94439e4e | 136 | |
137 | if (attribs & SMB_FA_DIR) | |
7c16470c | 138 | strcat(SMB_Attrib_Temp, (verbose?"Directory ":"D")); |
94439e4e | 139 | |
140 | if (attribs & SMB_FA_ARC) | |
7c16470c | 141 | strcat(SMB_Attrib_Temp, (verbose?"Archive ":"A")); |
94439e4e | 142 | |
7c16470c | 143 | return(SMB_Attrib_Temp); |
94439e4e | 144 | |
145 | } | |
146 | ||
7c16470c AJ |
147 | /* Pick up the Max Buffer Size from the Tree Structure ... */ |
148 | ||
149 | int SMB_Get_Tree_MBS(SMB_Tree_Handle tree) | |
150 | ||
94439e4e | 151 | { |
152 | if (tree != NULL) { | |
7c16470c | 153 | return(tree -> mbs); |
94439e4e | 154 | } else { |
7c16470c | 155 | return(SMBlibE_BAD); |
94439e4e | 156 | } |
157 | } | |
158 | ||
7c16470c AJ |
159 | /* Pick up the Max buffer size */ |
160 | ||
161 | int SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle) | |
162 | ||
94439e4e | 163 | { |
164 | if (Con_Handle != NULL) { | |
7c16470c | 165 | return(Con_Handle -> max_xmit); |
94439e4e | 166 | } else { |
7c16470c | 167 | return(SMBlibE_BAD); |
94439e4e | 168 | } |
169 | ||
170 | } | |
a19a836d | 171 | /* Pickup the protocol index from the connection structure */ |
7c16470c AJ |
172 | |
173 | int SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle) | |
174 | ||
94439e4e | 175 | { |
176 | if (Con_Handle != NULL) { | |
7c16470c | 177 | return(Con_Handle -> prot_IDX); |
94439e4e | 178 | } else { |
7c16470c | 179 | return(0xFFFF); /* Invalid protocol */ |
94439e4e | 180 | } |
181 | ||
182 | } | |
20a423f3 | 183 | #endif /* UNDEFINED */ |
94439e4e | 184 | |
7c16470c AJ |
185 | /* Pick up the protocol from the connection structure */ |
186 | ||
187 | int SMB_Get_Protocol(SMB_Handle_Type Con_Handle) | |
188 | ||
94439e4e | 189 | { |
190 | if (Con_Handle != NULL) { | |
7c16470c | 191 | return(Con_Handle -> protocol); |
94439e4e | 192 | } else { |
7c16470c | 193 | return(0xFFFF); /* Invalid protocol */ |
94439e4e | 194 | } |
195 | ||
196 | } | |
197 | ||
7c16470c AJ |
198 | /* Figure out what protocol was accepted, given the list of dialect strings */ |
199 | /* We offered, and the index back from the server. We allow for a user */ | |
200 | /* supplied list, and assume that it is a subset of our list */ | |
201 | ||
202 | int SMB_Figure_Protocol(const char *dialects[], int prot_index) | |
203 | ||
94439e4e | 204 | { |
205 | int i; | |
206 | ||
039b3598 AJ |
207 | // prot_index may be a value outside the table SMB_Types[] |
208 | // which holds data at offsets 0 to 11 | |
209 | int ourType = (prot_index < 0 || prot_index > 11); | |
210 | ||
211 | if (ourType && dialects == SMB_Prots) { /* The jobs is easy, just index into table */ | |
94439e4e | 212 | |
7c16470c AJ |
213 | return(SMB_Types[prot_index]); |
214 | } else { /* Search through SMB_Prots looking for a match */ | |
94439e4e | 215 | |
26ac0430 | 216 | for (i = 0; SMB_Prots[i] != NULL; i++) { |
94439e4e | 217 | |
7c16470c | 218 | if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) { /* A match */ |
94439e4e | 219 | |
7c16470c | 220 | return(SMB_Types[i]); |
94439e4e | 221 | |
26ac0430 | 222 | } |
7c16470c | 223 | |
26ac0430 | 224 | } |
94439e4e | 225 | |
26ac0430 AJ |
226 | /* If we got here, then we are in trouble, because the protocol was not */ |
227 | /* One we understand ... */ | |
94439e4e | 228 | |
7c16470c | 229 | return(SMB_P_Unknown); |
94439e4e | 230 | |
231 | } | |
232 | ||
233 | } | |
234 | ||
94439e4e | 235 | /* Negotiate the protocol we will use from the list passed in Prots */ |
236 | /* we return the index of the accepted protocol in NegProt, -1 indicates */ | |
2f8abb64 | 237 | /* none acceptable, and our return value is 0 if ok, <0 if problems */ |
94439e4e | 238 | |
7c16470c AJ |
239 | int SMB_Negotiate(SMB_Handle_Type Con_Handle, const char *Prots[]) |
240 | ||
94439e4e | 241 | { |
7c16470c AJ |
242 | // struct SMB_Neg_Prot_Def *prot_pkt; |
243 | // struct SMB_Neg_Prot_Resp_Def *resp_pkt; | |
94439e4e | 244 | struct RFCNB_Pkt *pkt; |
245 | int prots_len, i, pkt_len, prot, alloc_len; | |
246 | char *p; | |
247 | ||
248 | /* Figure out how long the prot list will be and allocate space for it */ | |
249 | ||
250 | prots_len = 0; | |
251 | ||
252 | for (i = 0; Prots[i] != NULL; i++) { | |
7c16470c AJ |
253 | |
254 | prots_len = prots_len + strlen(Prots[i]) + 2; /* Account for null etc */ | |
255 | ||
94439e4e | 256 | } |
257 | ||
258 | /* The -1 accounts for the one byte smb_buf we have because some systems */ | |
259 | /* don't like char msg_buf[] */ | |
260 | ||
261 | pkt_len = SMB_negp_len + prots_len; | |
262 | ||
263 | /* Make sure that the pkt len is long enough for the max response ... */ | |
264 | /* Which is a problem, because the encryption key len eec may be long */ | |
265 | ||
266 | if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) { | |
7c16470c | 267 | |
26ac0430 | 268 | alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40; |
7c16470c | 269 | |
94439e4e | 270 | } else { |
7c16470c | 271 | |
26ac0430 | 272 | alloc_len = pkt_len; |
7c16470c | 273 | |
94439e4e | 274 | } |
275 | ||
7c16470c | 276 | pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(alloc_len); |
94439e4e | 277 | |
278 | if (pkt == NULL) { | |
7c16470c | 279 | |
26ac0430 | 280 | SMBlib_errno = SMBlibE_NoSpace; |
7c16470c AJ |
281 | return(SMBlibE_BAD); |
282 | ||
94439e4e | 283 | } |
94439e4e | 284 | |
a19a836d | 285 | /* Now plug in the bits we need */ |
7c16470c | 286 | |
04830959 | 287 | memset(SMB_Hdr(pkt), 0, SMB_negp_len); |
7c16470c | 288 | SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ |
94439e4e | 289 | *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot; |
7c16470c | 290 | SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid); |
94439e4e | 291 | SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0); |
7c16470c AJ |
292 | SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid); |
293 | SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid); | |
94439e4e | 294 | *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; |
7c16470c | 295 | |
94439e4e | 296 | SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len); |
297 | ||
298 | /* Now copy the prot strings in with the right stuff */ | |
299 | ||
7c16470c | 300 | p = (char *)(SMB_Hdr(pkt) + SMB_negp_buf_offset); |
94439e4e | 301 | |
302 | for (i = 0; Prots[i] != NULL; i++) { | |
7c16470c | 303 | |
26ac0430 AJ |
304 | *p = SMBdialectID; |
305 | strcpy(p + 1, Prots[i]); | |
7c16470c AJ |
306 | p = p + strlen(Prots[i]) + 2; /* Adjust len of p for null plus dialectID */ |
307 | ||
94439e4e | 308 | } |
309 | ||
310 | /* Now send the packet and sit back ... */ | |
7c16470c AJ |
311 | |
312 | if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) { | |
313 | ||
94439e4e | 314 | #ifdef DEBUG |
26ac0430 | 315 | fprintf(stderr, "Error sending negotiate protocol\n"); |
94439e4e | 316 | #endif |
7c16470c | 317 | |
26ac0430 | 318 | RFCNB_Free_Pkt(pkt); |
7c16470c AJ |
319 | SMBlib_errno = -SMBlibE_SendFailed; /* Failed, check lower layer errno */ |
320 | return(SMBlibE_BAD); | |
321 | ||
94439e4e | 322 | } |
94439e4e | 323 | |
a19a836d | 324 | /* Now get the response ... */ |
7c16470c AJ |
325 | |
326 | if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, alloc_len) < 0) { | |
327 | ||
94439e4e | 328 | #ifdef DEBUG |
26ac0430 | 329 | fprintf(stderr, "Error receiving response to negotiate\n"); |
94439e4e | 330 | #endif |
7c16470c | 331 | |
26ac0430 | 332 | RFCNB_Free_Pkt(pkt); |
7c16470c AJ |
333 | SMBlib_errno = -SMBlibE_RecvFailed; /* Failed, check lower layer errno */ |
334 | return(SMBlibE_BAD); | |
335 | ||
94439e4e | 336 | } |
94439e4e | 337 | |
7c16470c AJ |
338 | if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ |
339 | ||
94439e4e | 340 | #ifdef DEBUG |
26ac0430 AJ |
341 | fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n", |
342 | CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), | |
343 | SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); | |
94439e4e | 344 | #endif |
7c16470c | 345 | |
26ac0430 AJ |
346 | SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); |
347 | RFCNB_Free_Pkt(pkt); | |
348 | SMBlib_errno = SMBlibE_Remote; | |
7c16470c AJ |
349 | return(SMBlibE_BAD); |
350 | ||
94439e4e | 351 | } |
94439e4e | 352 | |
a19a836d | 353 | if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) { |
7c16470c | 354 | |
94439e4e | 355 | #ifdef DEBUG |
26ac0430 | 356 | fprintf(stderr, "None of our protocols was accepted ... "); |
94439e4e | 357 | #endif |
7c16470c | 358 | |
26ac0430 AJ |
359 | RFCNB_Free_Pkt(pkt); |
360 | SMBlib_errno = SMBlibE_NegNoProt; | |
7c16470c AJ |
361 | return(SMBlibE_BAD); |
362 | ||
94439e4e | 363 | } |
a19a836d | 364 | |
94439e4e | 365 | /* Now, unpack the info from the response, if any and evaluate the proto */ |
366 | /* selected. We must make sure it is one we like ... */ | |
94439e4e | 367 | |
7c16470c AJ |
368 | Con_Handle -> prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset); |
369 | Con_Handle -> protocol = SMB_Figure_Protocol(Prots, prot); | |
370 | ||
371 | if (Con_Handle -> protocol == SMB_P_Unknown) { /* No good ... */ | |
372 | ||
26ac0430 AJ |
373 | RFCNB_Free_Pkt(pkt); |
374 | SMBlib_errno = SMBlibE_ProtUnknown; | |
7c16470c AJ |
375 | return(SMBlibE_BAD); |
376 | ||
94439e4e | 377 | } |
7c16470c | 378 | |
94439e4e | 379 | switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) { |
380 | ||
7c16470c AJ |
381 | case 0x01: /* No more info ... */ |
382 | ||
26ac0430 | 383 | break; |
94439e4e | 384 | |
7c16470c | 385 | case 13: /* Up to and including LanMan 2.1 */ |
94439e4e | 386 | |
7c16470c AJ |
387 | Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset); |
388 | Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00); | |
389 | Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask; | |
94439e4e | 390 | |
7c16470c AJ |
391 | Con_Handle -> max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset); |
392 | Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset); | |
393 | Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset); | |
394 | Con_Handle -> Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset); | |
395 | Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset); | |
396 | Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset); | |
397 | Con_Handle -> Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset); | |
94439e4e | 398 | |
26ac0430 | 399 | p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset); |
26ac0430 | 400 | memcpy(Con_Handle->Encrypt_Key, p, 8); |
94439e4e | 401 | |
7c16470c AJ |
402 | p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len); |
403 | ||
02fc37ca | 404 | xstrncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom)); |
94439e4e | 405 | |
26ac0430 | 406 | break; |
94439e4e | 407 | |
7c16470c | 408 | case 17: /* NT LM 0.12 and LN LM 1.0 */ |
94439e4e | 409 | |
7c16470c AJ |
410 | Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset); |
411 | Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00); | |
412 | Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask; | |
94439e4e | 413 | |
7c16470c AJ |
414 | Con_Handle -> max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset); |
415 | Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset); | |
416 | Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset); | |
417 | Con_Handle -> MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset); | |
418 | Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset); | |
419 | Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset); | |
420 | Con_Handle -> Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset); | |
94439e4e | 421 | |
26ac0430 AJ |
422 | p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset); |
423 | memcpy(Con_Handle->Encrypt_Key, p, 8); | |
94439e4e | 424 | |
7c16470c AJ |
425 | p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len); |
426 | ||
02fc37ca | 427 | xstrncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom)); |
94439e4e | 428 | |
26ac0430 | 429 | break; |
94439e4e | 430 | |
431 | default: | |
432 | ||
433 | #ifdef DEBUG | |
26ac0430 AJ |
434 | fprintf(stderr, "Unknown NegProt response format ... Ignored\n"); |
435 | fprintf(stderr, " wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)); | |
94439e4e | 436 | #endif |
437 | ||
26ac0430 | 438 | break; |
94439e4e | 439 | } |
440 | ||
441 | #ifdef DEBUG | |
442 | fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]); | |
443 | #endif | |
444 | ||
445 | RFCNB_Free_Pkt(pkt); | |
7c16470c | 446 | return(0); |
94439e4e | 447 | |
448 | } | |
449 | ||
450 | /* Get our hostname */ | |
451 | ||
7c16470c | 452 | void SMB_Get_My_Name(char *name, int len) |
94439e4e | 453 | |
7c16470c AJ |
454 | { |
455 | if (gethostname(name, len) < 0) { /* Error getting name */ | |
94439e4e | 456 | |
26ac0430 | 457 | strncpy(name, "unknown", len); |
94439e4e | 458 | |
26ac0430 | 459 | /* Should check the error */ |
94439e4e | 460 | |
461 | #ifdef DEBUG | |
26ac0430 AJ |
462 | fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:"); |
463 | perror(""); | |
94439e4e | 464 | #endif |
465 | ||
7c16470c AJ |
466 | } else { |
467 | char *address; | |
468 | /* only keep the portion up to the first "." */ | |
469 | if (NULL != (address = strchr(name, '.'))) { | |
3c96dd46 | 470 | *address = '\0'; /* truncate at first '.' */ |
7c16470c | 471 | } |
94439e4e | 472 | } |
94439e4e | 473 | } |
474 | ||
475 | /* Send a TCON to the remote server ... */ | |
476 | ||
7c16470c AJ |
477 | SMB_Tree_Handle SMB_TreeConnect(SMB_Handle_Type Con_Handle, |
478 | SMB_Tree_Handle Tree_Handle, | |
479 | const char *path, | |
480 | const char *password, | |
481 | const char *device) | |
482 | ||
94439e4e | 483 | { |
484 | struct RFCNB_Pkt *pkt; | |
485 | int param_len, pkt_len; | |
486 | char *p; | |
487 | SMB_Tree_Handle tree; | |
488 | ||
489 | /* Figure out how much space is needed for path, password, dev ... */ | |
490 | ||
7c16470c | 491 | if ((path == NULL) | (password == NULL) | (device == NULL)) { |
94439e4e | 492 | |
493 | #ifdef DEBUG | |
26ac0430 | 494 | fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n"); |
94439e4e | 495 | #endif |
496 | ||
26ac0430 | 497 | SMBlib_errno = SMBlibE_BadParam; |
7c16470c | 498 | return(NULL); |
94439e4e | 499 | |
500 | } | |
7c16470c | 501 | |
94439e4e | 502 | /* The + 2 is because of the \0 and the marker ... */ |
503 | ||
504 | param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2; | |
505 | ||
506 | /* The -1 accounts for the one byte smb_buf we have because some systems */ | |
507 | /* don't like char msg_buf[] */ | |
508 | ||
509 | pkt_len = SMB_tcon_len + param_len; | |
510 | ||
7c16470c | 511 | pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); |
94439e4e | 512 | |
513 | if (pkt == NULL) { | |
514 | ||
26ac0430 | 515 | SMBlib_errno = SMBlibE_NoSpace; |
7c16470c | 516 | return(NULL); /* Should handle the error */ |
94439e4e | 517 | |
518 | } | |
7c16470c | 519 | |
94439e4e | 520 | /* Now allocate a tree for this to go into ... */ |
521 | ||
522 | if (Tree_Handle == NULL) { | |
523 | ||
7c16470c | 524 | tree = (SMB_Tree_Handle)malloc(sizeof(struct SMB_Tree_Structure)); |
94439e4e | 525 | |
26ac0430 | 526 | if (tree == NULL) { |
94439e4e | 527 | |
26ac0430 AJ |
528 | RFCNB_Free_Pkt(pkt); |
529 | SMBlib_errno = SMBlibE_NoSpace; | |
7c16470c | 530 | return(NULL); |
94439e4e | 531 | |
26ac0430 | 532 | } |
94439e4e | 533 | } else { |
534 | ||
26ac0430 | 535 | tree = Tree_Handle; |
94439e4e | 536 | |
537 | } | |
538 | ||
7c16470c AJ |
539 | tree -> next = tree -> prev = NULL; |
540 | tree -> con = Con_Handle; | |
02fc37ca AJ |
541 | xstrncpy(tree -> path, path, sizeof(tree -> path)); |
542 | xstrncpy(tree -> device_type, device, sizeof(tree -> device_type)); | |
94439e4e | 543 | |
544 | /* Now plug in the values ... */ | |
545 | ||
04830959 | 546 | memset(SMB_Hdr(pkt), 0, SMB_tcon_len); |
7c16470c | 547 | SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ |
94439e4e | 548 | *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon; |
7c16470c | 549 | SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid); |
94439e4e | 550 | SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0); |
7c16470c AJ |
551 | SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid); |
552 | SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid); | |
94439e4e | 553 | *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; |
554 | ||
555 | SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, param_len); | |
556 | ||
557 | /* Now copy the param strings in with the right stuff */ | |
558 | ||
7c16470c | 559 | p = (char *)(SMB_Hdr(pkt) + SMB_tcon_buf_offset); |
94439e4e | 560 | *p = SMBasciiID; |
561 | strcpy(p + 1, path); | |
562 | p = p + strlen(path) + 2; | |
563 | *p = SMBasciiID; | |
564 | strcpy(p + 1, password); | |
565 | p = p + strlen(password) + 2; | |
566 | *p = SMBasciiID; | |
567 | strcpy(p + 1, device); | |
568 | ||
569 | /* Now send the packet and sit back ... */ | |
570 | ||
7c16470c | 571 | if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) { |
94439e4e | 572 | |
573 | #ifdef DEBUG | |
26ac0430 | 574 | fprintf(stderr, "Error sending TCon request\n"); |
94439e4e | 575 | #endif |
576 | ||
26ac0430 AJ |
577 | if (Tree_Handle == NULL) |
578 | free(tree); | |
579 | RFCNB_Free_Pkt(pkt); | |
580 | SMBlib_errno = -SMBlibE_SendFailed; | |
7c16470c | 581 | return(NULL); |
94439e4e | 582 | |
583 | } | |
7c16470c | 584 | |
94439e4e | 585 | /* Now get the response ... */ |
586 | ||
7c16470c | 587 | if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) { |
94439e4e | 588 | |
589 | #ifdef DEBUG | |
26ac0430 | 590 | fprintf(stderr, "Error receiving response to TCon\n"); |
94439e4e | 591 | #endif |
592 | ||
26ac0430 AJ |
593 | if (Tree_Handle == NULL) |
594 | free(tree); | |
595 | RFCNB_Free_Pkt(pkt); | |
596 | SMBlib_errno = -SMBlibE_RecvFailed; | |
7c16470c | 597 | return(NULL); |
94439e4e | 598 | |
599 | } | |
7c16470c | 600 | |
94439e4e | 601 | /* Check out the response type ... */ |
602 | ||
7c16470c | 603 | if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ |
94439e4e | 604 | |
605 | #ifdef DEBUG | |
26ac0430 AJ |
606 | fprintf(stderr, "SMB_TCon failed with errorclass = %i, Error Code = %i\n", |
607 | CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), | |
608 | SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); | |
94439e4e | 609 | #endif |
610 | ||
26ac0430 AJ |
611 | if (Tree_Handle == NULL) |
612 | free(tree); | |
613 | SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); | |
614 | RFCNB_Free_Pkt(pkt); | |
615 | SMBlib_errno = SMBlibE_Remote; | |
7c16470c | 616 | return(NULL); |
94439e4e | 617 | |
618 | } | |
7c16470c AJ |
619 | |
620 | tree -> tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset); | |
621 | tree -> mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset); | |
94439e4e | 622 | |
623 | #ifdef DEBUG | |
624 | fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n", | |
7c16470c | 625 | tree -> tid, tree -> mbs); |
94439e4e | 626 | #endif |
627 | ||
628 | /* Now link the Tree to the Server Structure ... */ | |
629 | ||
7c16470c | 630 | if (Con_Handle -> first_tree == NULL) { |
94439e4e | 631 | |
7c16470c AJ |
632 | Con_Handle -> first_tree = tree; |
633 | Con_Handle -> last_tree = tree; | |
94439e4e | 634 | |
635 | } else { | |
636 | ||
7c16470c AJ |
637 | Con_Handle -> last_tree -> next = tree; |
638 | tree -> prev = Con_Handle -> last_tree; | |
639 | Con_Handle -> last_tree = tree; | |
94439e4e | 640 | |
641 | } | |
642 | ||
643 | RFCNB_Free_Pkt(pkt); | |
7c16470c | 644 | return(tree); |
94439e4e | 645 | |
646 | } | |
647 | ||
7c16470c AJ |
648 | int SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard) |
649 | ||
94439e4e | 650 | { |
651 | struct RFCNB_Pkt *pkt; | |
652 | int pkt_len; | |
653 | ||
654 | pkt_len = SMB_tdis_len; | |
655 | ||
7c16470c | 656 | pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); |
94439e4e | 657 | |
658 | if (pkt == NULL) { | |
659 | ||
26ac0430 | 660 | SMBlib_errno = SMBlibE_NoSpace; |
7c16470c | 661 | return(SMBlibE_BAD); /* Should handle the error */ |
94439e4e | 662 | |
663 | } | |
7c16470c | 664 | |
94439e4e | 665 | /* Now plug in the values ... */ |
666 | ||
04830959 | 667 | memset(SMB_Hdr(pkt), 0, SMB_tdis_len); |
7c16470c | 668 | SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ |
94439e4e | 669 | *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis; |
7c16470c AJ |
670 | SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle -> con -> pid); |
671 | SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle -> con -> mid); | |
672 | SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle -> con -> uid); | |
94439e4e | 673 | *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; |
674 | ||
7c16470c | 675 | SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle -> tid); |
94439e4e | 676 | SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0); |
677 | ||
678 | /* Now send the packet and sit back ... */ | |
679 | ||
7c16470c | 680 | if (RFCNB_Send(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) { |
94439e4e | 681 | |
682 | #ifdef DEBUG | |
26ac0430 | 683 | fprintf(stderr, "Error sending TDis request\n"); |
94439e4e | 684 | #endif |
685 | ||
26ac0430 AJ |
686 | RFCNB_Free_Pkt(pkt); |
687 | SMBlib_errno = -SMBlibE_SendFailed; | |
7c16470c | 688 | return(SMBlibE_BAD); |
94439e4e | 689 | |
690 | } | |
7c16470c | 691 | |
94439e4e | 692 | /* Now get the response ... */ |
693 | ||
7c16470c | 694 | if (RFCNB_Recv(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) { |
94439e4e | 695 | |
696 | #ifdef DEBUG | |
26ac0430 | 697 | fprintf(stderr, "Error receiving response to TCon\n"); |
94439e4e | 698 | #endif |
699 | ||
26ac0430 AJ |
700 | RFCNB_Free_Pkt(pkt); |
701 | SMBlib_errno = -SMBlibE_RecvFailed; | |
7c16470c | 702 | return(SMBlibE_BAD); |
94439e4e | 703 | |
704 | } | |
7c16470c | 705 | |
94439e4e | 706 | /* Check out the response type ... */ |
707 | ||
7c16470c | 708 | if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ |
94439e4e | 709 | |
710 | #ifdef DEBUG | |
26ac0430 AJ |
711 | fprintf(stderr, "SMB_TDis failed with errorclass = %i, Error Code = %i\n", |
712 | CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), | |
713 | SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); | |
94439e4e | 714 | #endif |
715 | ||
26ac0430 AJ |
716 | SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); |
717 | RFCNB_Free_Pkt(pkt); | |
718 | SMBlib_errno = SMBlibE_Remote; | |
7c16470c | 719 | return(SMBlibE_BAD); |
94439e4e | 720 | |
721 | } | |
7c16470c AJ |
722 | |
723 | Tree_Handle -> tid = 0xFFFF; /* Invalid TID */ | |
724 | Tree_Handle -> mbs = 0; /* Invalid */ | |
94439e4e | 725 | |
726 | #ifdef DEBUG | |
727 | ||
728 | fprintf(stderr, "Tree disconnect successful ...\n"); | |
729 | ||
730 | #endif | |
731 | ||
732 | /* What about the tree handle ? */ | |
733 | ||
7c16470c | 734 | if (discard == TRUE) { /* Unlink it and free it ... */ |
94439e4e | 735 | |
7c16470c AJ |
736 | if (Tree_Handle -> next == NULL) |
737 | Tree_Handle -> con -> first_tree = Tree_Handle -> prev; | |
26ac0430 | 738 | else |
7c16470c | 739 | Tree_Handle -> next -> prev = Tree_Handle -> prev; |
94439e4e | 740 | |
7c16470c AJ |
741 | if (Tree_Handle -> prev == NULL) |
742 | Tree_Handle -> con -> last_tree = Tree_Handle -> next; | |
26ac0430 | 743 | else |
7c16470c | 744 | Tree_Handle -> prev -> next = Tree_Handle -> next; |
94439e4e | 745 | |
746 | } | |
7c16470c | 747 | |
94439e4e | 748 | RFCNB_Free_Pkt(pkt); |
7c16470c | 749 | return(0); |
94439e4e | 750 | |
751 | } | |
752 | ||
753 | /* Pick up the last LMBlib error ... */ | |
754 | ||
7c16470c AJ |
755 | int SMB_Get_Last_Error() |
756 | ||
94439e4e | 757 | { |
758 | ||
7c16470c | 759 | return(SMBlib_errno); |
94439e4e | 760 | |
761 | } | |
762 | ||
7c16470c AJ |
763 | /* Pick up the last error returned in an SMB packet */ |
764 | /* We will need macros to extract error class and error code */ | |
765 | ||
766 | int SMB_Get_Last_SMB_Err() | |
767 | ||
94439e4e | 768 | { |
769 | ||
7c16470c | 770 | return(SMBlib_SMB_Error); |
94439e4e | 771 | |
772 | } | |
773 | ||
774 | /* Pick up the error message associated with an error from SMBlib */ | |
775 | ||
776 | /* Keep this table in sync with the message codes in smblib-common.h */ | |
777 | ||
7c16470c | 778 | static const char *SMBlib_Error_Messages[] = { |
94439e4e | 779 | |
14e9491b | 780 | "Request completed successfully.", |
94439e4e | 781 | "Server returned a non-zero SMB Error Class and Code.", |
782 | "A lower layer protocol error occurred.", | |
783 | "Function not yet implemented.", | |
784 | "The protocol negotiated does not support the request.", | |
785 | "No space available for operation.", | |
786 | "One or more bad parameters passed.", | |
787 | "None of the protocols we offered were accepted.", | |
788 | "The attempt to send an SMB request failed. See protocol error info.", | |
789 | "The attempt to get an SMB response failed. See protocol error info.", | |
790 | "The logon request failed, but you were logged in as guest.", | |
791 | "The attempt to call the remote server failed. See protocol error info.", | |
792 | "The protocol dialect specified in a NegProt and accepted by the server is unknown.", | |
26ac0430 | 793 | /* This next one simplifies error handling */ |
94439e4e | 794 | "No such error code.", |
26ac0430 AJ |
795 | NULL |
796 | }; | |
94439e4e | 797 | |
7c16470c AJ |
798 | void SMB_Get_Error_Msg(int msg, char *msgbuf, int len) |
799 | ||
94439e4e | 800 | { |
801 | ||
802 | if (msg >= 0) { | |
803 | ||
26ac0430 | 804 | strncpy(msgbuf, |
7c16470c | 805 | SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg], |
26ac0430 | 806 | len - 1); |
7c16470c AJ |
807 | msgbuf[len - 1] = 0; /* Make sure it is a string */ |
808 | } else { /* Add the lower layer message ... */ | |
94439e4e | 809 | |
26ac0430 | 810 | char prot_msg[1024]; |
94439e4e | 811 | |
7c16470c | 812 | msg = -msg; /* Make it positive */ |
94439e4e | 813 | |
26ac0430 | 814 | strncpy(msgbuf, |
7c16470c | 815 | SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg], |
26ac0430 | 816 | len - 1); |
94439e4e | 817 | |
7c16470c | 818 | msgbuf[len - 1] = 0; /* make sure it is a string */ |
94439e4e | 819 | |
7c16470c | 820 | if (strlen(msgbuf) < len) { /* If there is space, put rest in */ |
94439e4e | 821 | |
26ac0430 | 822 | strncat(msgbuf, "\n\t", len - strlen(msgbuf)); |
94439e4e | 823 | |
26ac0430 | 824 | RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1); |
94439e4e | 825 | |
26ac0430 | 826 | strncat(msgbuf, prot_msg, len - strlen(msgbuf)); |
94439e4e | 827 | |
26ac0430 | 828 | } |
94439e4e | 829 | } |
7c16470c | 830 | |
94439e4e | 831 | } |
f53969cc | 832 |