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