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