]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2025 The Squid Software Foundation and contributors | |
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 | */ | |
8 | ||
9 | /* UNIX SMBlib NetBIOS implementation | |
10 | ||
11 | Version 1.0 | |
12 | SMBlib Utility Routines | |
13 | ||
14 | Copyright (C) Richard Sharpe 1996 | |
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 | ||
33 | #include "squid.h" | |
34 | #include "rfcnb/rfcnb.h" | |
35 | #include "smblib/smblib-priv.h" | |
36 | #include "smblib/smblib.h" | |
37 | ||
38 | #if HAVE_STRING_H | |
39 | #include <string.h> | |
40 | #endif | |
41 | ||
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 | }; | |
56 | ||
57 | #if UNDEFINED | |
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); | |
63 | #endif /* UNDEFINED */ | |
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); | |
67 | ||
68 | #if UNDEFINED | |
69 | /* Print out an SMB pkt in all its gory detail ... */ | |
70 | ||
71 | void SMB_Print_Pkt(FILE fd, RFCNB_Pkt *pkt, BOOL command, int Offset, int Len) | |
72 | ||
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 | ||
83 | /* etc */ | |
84 | ||
85 | } | |
86 | #endif | |
87 | ||
88 | /* Convert a DOS Date_Time to a local host type date time for printing */ | |
89 | ||
90 | #if UNDEFINED | |
91 | char *SMB_DOSTimToStr(int DOS_time) | |
92 | ||
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 | ||
99 | DOS_sec = (DOS_time & 0x001F) * 2; | |
100 | DOS_min = (DOS_time & 0x07E0) >> 5; | |
101 | DOS_hour = ((DOS_time & 0xF800) >> 11); | |
102 | ||
103 | DOS_day = (DOS_time & 0x001F0000) >> 16; | |
104 | DOS_month = (DOS_time & 0x01E00000) >> 21; | |
105 | DOS_year = ((DOS_time & 0xFE000000) >> 25) + 80; | |
106 | ||
107 | snprintf(SMB_Time_Temp, 48, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month, | |
108 | DOS_year, DOS_hour, DOS_min, DOS_sec); | |
109 | ||
110 | return(SMB_Time_Temp); | |
111 | ||
112 | } | |
113 | ||
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 | ||
120 | { | |
121 | static char SMB_Attrib_Temp[128]; | |
122 | ||
123 | SMB_Attrib_Temp[0] = 0; | |
124 | ||
125 | if (attribs & SMB_FA_ROF) | |
126 | strcat(SMB_Attrib_Temp, (verbose?"Read Only ":"R")); | |
127 | ||
128 | if (attribs & SMB_FA_HID) | |
129 | strcat(SMB_Attrib_Temp, (verbose?"Hidden ":"H")); | |
130 | ||
131 | if (attribs & SMB_FA_SYS) | |
132 | strcat(SMB_Attrib_Temp, (verbose?"System ":"S")); | |
133 | ||
134 | if (attribs & SMB_FA_VOL) | |
135 | strcat(SMB_Attrib_Temp, (verbose?"Volume ":"V")); | |
136 | ||
137 | if (attribs & SMB_FA_DIR) | |
138 | strcat(SMB_Attrib_Temp, (verbose?"Directory ":"D")); | |
139 | ||
140 | if (attribs & SMB_FA_ARC) | |
141 | strcat(SMB_Attrib_Temp, (verbose?"Archive ":"A")); | |
142 | ||
143 | return(SMB_Attrib_Temp); | |
144 | ||
145 | } | |
146 | ||
147 | /* Pick up the Max Buffer Size from the Tree Structure ... */ | |
148 | ||
149 | int SMB_Get_Tree_MBS(SMB_Tree_Handle tree) | |
150 | ||
151 | { | |
152 | if (tree != NULL) { | |
153 | return(tree -> mbs); | |
154 | } else { | |
155 | return(SMBlibE_BAD); | |
156 | } | |
157 | } | |
158 | ||
159 | /* Pick up the Max buffer size */ | |
160 | ||
161 | int SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle) | |
162 | ||
163 | { | |
164 | if (Con_Handle != NULL) { | |
165 | return(Con_Handle -> max_xmit); | |
166 | } else { | |
167 | return(SMBlibE_BAD); | |
168 | } | |
169 | ||
170 | } | |
171 | /* Pickup the protocol index from the connection structure */ | |
172 | ||
173 | int SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle) | |
174 | ||
175 | { | |
176 | if (Con_Handle != NULL) { | |
177 | return(Con_Handle -> prot_IDX); | |
178 | } else { | |
179 | return(0xFFFF); /* Invalid protocol */ | |
180 | } | |
181 | ||
182 | } | |
183 | #endif /* UNDEFINED */ | |
184 | ||
185 | /* Pick up the protocol from the connection structure */ | |
186 | ||
187 | int SMB_Get_Protocol(SMB_Handle_Type Con_Handle) | |
188 | ||
189 | { | |
190 | if (Con_Handle != NULL) { | |
191 | return(Con_Handle -> protocol); | |
192 | } else { | |
193 | return(0xFFFF); /* Invalid protocol */ | |
194 | } | |
195 | ||
196 | } | |
197 | ||
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 | ||
204 | { | |
205 | int i; | |
206 | ||
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 */ | |
212 | ||
213 | return(SMB_Types[prot_index]); | |
214 | } else { /* Search through SMB_Prots looking for a match */ | |
215 | ||
216 | for (i = 0; SMB_Prots[i] != NULL; i++) { | |
217 | ||
218 | if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) { /* A match */ | |
219 | ||
220 | return(SMB_Types[i]); | |
221 | ||
222 | } | |
223 | ||
224 | } | |
225 | ||
226 | /* If we got here, then we are in trouble, because the protocol was not */ | |
227 | /* One we understand ... */ | |
228 | ||
229 | return(SMB_P_Unknown); | |
230 | ||
231 | } | |
232 | ||
233 | } | |
234 | ||
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 */ | |
237 | /* none acceptable, and our return value is 0 if ok, <0 if problems */ | |
238 | ||
239 | int SMB_Negotiate(SMB_Handle_Type Con_Handle, const char *Prots[]) | |
240 | ||
241 | { | |
242 | // struct SMB_Neg_Prot_Def *prot_pkt; | |
243 | // struct SMB_Neg_Prot_Resp_Def *resp_pkt; | |
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++) { | |
253 | ||
254 | prots_len = prots_len + strlen(Prots[i]) + 2; /* Account for null etc */ | |
255 | ||
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)) { | |
267 | ||
268 | alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40; | |
269 | ||
270 | } else { | |
271 | ||
272 | alloc_len = pkt_len; | |
273 | ||
274 | } | |
275 | ||
276 | pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(alloc_len); | |
277 | ||
278 | if (pkt == NULL) { | |
279 | ||
280 | SMBlib_errno = SMBlibE_NoSpace; | |
281 | return(SMBlibE_BAD); | |
282 | ||
283 | } | |
284 | ||
285 | /* Now plug in the bits we need */ | |
286 | ||
287 | memset(SMB_Hdr(pkt), 0, SMB_negp_len); | |
288 | SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ | |
289 | *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot; | |
290 | SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid); | |
291 | SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0); | |
292 | SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid); | |
293 | SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid); | |
294 | *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; | |
295 | ||
296 | SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len); | |
297 | ||
298 | /* Now copy the prot strings in with the right stuff */ | |
299 | ||
300 | p = (char *)(SMB_Hdr(pkt) + SMB_negp_buf_offset); | |
301 | ||
302 | for (i = 0; Prots[i] != NULL; i++) { | |
303 | ||
304 | *p = SMBdialectID; | |
305 | strcpy(p + 1, Prots[i]); | |
306 | p = p + strlen(Prots[i]) + 2; /* Adjust len of p for null plus dialectID */ | |
307 | ||
308 | } | |
309 | ||
310 | /* Now send the packet and sit back ... */ | |
311 | ||
312 | if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) { | |
313 | ||
314 | #ifdef DEBUG | |
315 | fprintf(stderr, "Error sending negotiate protocol\n"); | |
316 | #endif | |
317 | ||
318 | RFCNB_Free_Pkt(pkt); | |
319 | SMBlib_errno = -SMBlibE_SendFailed; /* Failed, check lower layer errno */ | |
320 | return(SMBlibE_BAD); | |
321 | ||
322 | } | |
323 | ||
324 | /* Now get the response ... */ | |
325 | ||
326 | if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, alloc_len) < 0) { | |
327 | ||
328 | #ifdef DEBUG | |
329 | fprintf(stderr, "Error receiving response to negotiate\n"); | |
330 | #endif | |
331 | ||
332 | RFCNB_Free_Pkt(pkt); | |
333 | SMBlib_errno = -SMBlibE_RecvFailed; /* Failed, check lower layer errno */ | |
334 | return(SMBlibE_BAD); | |
335 | ||
336 | } | |
337 | ||
338 | if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ | |
339 | ||
340 | #ifdef DEBUG | |
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)); | |
344 | #endif | |
345 | ||
346 | SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); | |
347 | RFCNB_Free_Pkt(pkt); | |
348 | SMBlib_errno = SMBlibE_Remote; | |
349 | return(SMBlibE_BAD); | |
350 | ||
351 | } | |
352 | ||
353 | if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) { | |
354 | ||
355 | #ifdef DEBUG | |
356 | fprintf(stderr, "None of our protocols was accepted ... "); | |
357 | #endif | |
358 | ||
359 | RFCNB_Free_Pkt(pkt); | |
360 | SMBlib_errno = SMBlibE_NegNoProt; | |
361 | return(SMBlibE_BAD); | |
362 | ||
363 | } | |
364 | ||
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 ... */ | |
367 | ||
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 | ||
373 | RFCNB_Free_Pkt(pkt); | |
374 | SMBlib_errno = SMBlibE_ProtUnknown; | |
375 | return(SMBlibE_BAD); | |
376 | ||
377 | } | |
378 | ||
379 | switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) { | |
380 | ||
381 | case 0x01: /* No more info ... */ | |
382 | ||
383 | break; | |
384 | ||
385 | case 13: /* Up to and including LanMan 2.1 */ | |
386 | ||
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; | |
390 | ||
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); | |
398 | ||
399 | p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset); | |
400 | memcpy(Con_Handle->Encrypt_Key, p, 8); | |
401 | ||
402 | p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len); | |
403 | ||
404 | xstrncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom)); | |
405 | ||
406 | break; | |
407 | ||
408 | case 17: /* NT LM 0.12 and LN LM 1.0 */ | |
409 | ||
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; | |
413 | ||
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); | |
421 | ||
422 | p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset); | |
423 | memcpy(Con_Handle->Encrypt_Key, p, 8); | |
424 | ||
425 | p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len); | |
426 | ||
427 | xstrncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom)); | |
428 | ||
429 | break; | |
430 | ||
431 | default: | |
432 | ||
433 | #ifdef DEBUG | |
434 | fprintf(stderr, "Unknown NegProt response format ... Ignored\n"); | |
435 | fprintf(stderr, " wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)); | |
436 | #endif | |
437 | ||
438 | break; | |
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); | |
446 | return(0); | |
447 | ||
448 | } | |
449 | ||
450 | /* Get our hostname */ | |
451 | ||
452 | void SMB_Get_My_Name(char *name, int len) | |
453 | ||
454 | { | |
455 | if (gethostname(name, len) < 0) { /* Error getting name */ | |
456 | ||
457 | strncpy(name, "unknown", len); | |
458 | ||
459 | /* Should check the error */ | |
460 | ||
461 | #ifdef DEBUG | |
462 | fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:"); | |
463 | perror(""); | |
464 | #endif | |
465 | ||
466 | } else { | |
467 | char *address; | |
468 | /* only keep the portion up to the first "." */ | |
469 | if (NULL != (address = strchr(name, '.'))) { | |
470 | *address = '\0'; /* truncate at first '.' */ | |
471 | } | |
472 | } | |
473 | } | |
474 | ||
475 | /* Send a TCON to the remote server ... */ | |
476 | ||
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 | ||
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 | ||
491 | if ((path == NULL) | (password == NULL) | (device == NULL)) { | |
492 | ||
493 | #ifdef DEBUG | |
494 | fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n"); | |
495 | #endif | |
496 | ||
497 | SMBlib_errno = SMBlibE_BadParam; | |
498 | return(NULL); | |
499 | ||
500 | } | |
501 | ||
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 | ||
511 | pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); | |
512 | ||
513 | if (pkt == NULL) { | |
514 | ||
515 | SMBlib_errno = SMBlibE_NoSpace; | |
516 | return(NULL); /* Should handle the error */ | |
517 | ||
518 | } | |
519 | ||
520 | /* Now allocate a tree for this to go into ... */ | |
521 | ||
522 | if (Tree_Handle == NULL) { | |
523 | ||
524 | tree = (SMB_Tree_Handle)malloc(sizeof(struct SMB_Tree_Structure)); | |
525 | ||
526 | if (tree == NULL) { | |
527 | ||
528 | RFCNB_Free_Pkt(pkt); | |
529 | SMBlib_errno = SMBlibE_NoSpace; | |
530 | return(NULL); | |
531 | ||
532 | } | |
533 | } else { | |
534 | ||
535 | tree = Tree_Handle; | |
536 | ||
537 | } | |
538 | ||
539 | tree -> next = tree -> prev = NULL; | |
540 | tree -> con = Con_Handle; | |
541 | xstrncpy(tree -> path, path, sizeof(tree -> path)); | |
542 | xstrncpy(tree -> device_type, device, sizeof(tree -> device_type)); | |
543 | ||
544 | /* Now plug in the values ... */ | |
545 | ||
546 | memset(SMB_Hdr(pkt), 0, SMB_tcon_len); | |
547 | SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ | |
548 | *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon; | |
549 | SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid); | |
550 | SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0); | |
551 | SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid); | |
552 | SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid); | |
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 | ||
559 | p = (char *)(SMB_Hdr(pkt) + SMB_tcon_buf_offset); | |
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 | ||
571 | if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) { | |
572 | ||
573 | #ifdef DEBUG | |
574 | fprintf(stderr, "Error sending TCon request\n"); | |
575 | #endif | |
576 | ||
577 | if (Tree_Handle == NULL) | |
578 | free(tree); | |
579 | RFCNB_Free_Pkt(pkt); | |
580 | SMBlib_errno = -SMBlibE_SendFailed; | |
581 | return(NULL); | |
582 | ||
583 | } | |
584 | ||
585 | /* Now get the response ... */ | |
586 | ||
587 | if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) { | |
588 | ||
589 | #ifdef DEBUG | |
590 | fprintf(stderr, "Error receiving response to TCon\n"); | |
591 | #endif | |
592 | ||
593 | if (Tree_Handle == NULL) | |
594 | free(tree); | |
595 | RFCNB_Free_Pkt(pkt); | |
596 | SMBlib_errno = -SMBlibE_RecvFailed; | |
597 | return(NULL); | |
598 | ||
599 | } | |
600 | ||
601 | /* Check out the response type ... */ | |
602 | ||
603 | if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ | |
604 | ||
605 | #ifdef DEBUG | |
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)); | |
609 | #endif | |
610 | ||
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; | |
616 | return(NULL); | |
617 | ||
618 | } | |
619 | ||
620 | tree -> tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset); | |
621 | tree -> mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset); | |
622 | ||
623 | #ifdef DEBUG | |
624 | fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n", | |
625 | tree -> tid, tree -> mbs); | |
626 | #endif | |
627 | ||
628 | /* Now link the Tree to the Server Structure ... */ | |
629 | ||
630 | if (Con_Handle -> first_tree == NULL) { | |
631 | ||
632 | Con_Handle -> first_tree = tree; | |
633 | Con_Handle -> last_tree = tree; | |
634 | ||
635 | } else { | |
636 | ||
637 | Con_Handle -> last_tree -> next = tree; | |
638 | tree -> prev = Con_Handle -> last_tree; | |
639 | Con_Handle -> last_tree = tree; | |
640 | ||
641 | } | |
642 | ||
643 | RFCNB_Free_Pkt(pkt); | |
644 | return(tree); | |
645 | ||
646 | } | |
647 | ||
648 | int SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard) | |
649 | ||
650 | { | |
651 | struct RFCNB_Pkt *pkt; | |
652 | int pkt_len; | |
653 | ||
654 | pkt_len = SMB_tdis_len; | |
655 | ||
656 | pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); | |
657 | ||
658 | if (pkt == NULL) { | |
659 | ||
660 | SMBlib_errno = SMBlibE_NoSpace; | |
661 | return(SMBlibE_BAD); /* Should handle the error */ | |
662 | ||
663 | } | |
664 | ||
665 | /* Now plug in the values ... */ | |
666 | ||
667 | memset(SMB_Hdr(pkt), 0, SMB_tdis_len); | |
668 | SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ | |
669 | *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis; | |
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); | |
673 | *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; | |
674 | ||
675 | SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle -> tid); | |
676 | SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0); | |
677 | ||
678 | /* Now send the packet and sit back ... */ | |
679 | ||
680 | if (RFCNB_Send(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) { | |
681 | ||
682 | #ifdef DEBUG | |
683 | fprintf(stderr, "Error sending TDis request\n"); | |
684 | #endif | |
685 | ||
686 | RFCNB_Free_Pkt(pkt); | |
687 | SMBlib_errno = -SMBlibE_SendFailed; | |
688 | return(SMBlibE_BAD); | |
689 | ||
690 | } | |
691 | ||
692 | /* Now get the response ... */ | |
693 | ||
694 | if (RFCNB_Recv(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) { | |
695 | ||
696 | #ifdef DEBUG | |
697 | fprintf(stderr, "Error receiving response to TCon\n"); | |
698 | #endif | |
699 | ||
700 | RFCNB_Free_Pkt(pkt); | |
701 | SMBlib_errno = -SMBlibE_RecvFailed; | |
702 | return(SMBlibE_BAD); | |
703 | ||
704 | } | |
705 | ||
706 | /* Check out the response type ... */ | |
707 | ||
708 | if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ | |
709 | ||
710 | #ifdef DEBUG | |
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)); | |
714 | #endif | |
715 | ||
716 | SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); | |
717 | RFCNB_Free_Pkt(pkt); | |
718 | SMBlib_errno = SMBlibE_Remote; | |
719 | return(SMBlibE_BAD); | |
720 | ||
721 | } | |
722 | ||
723 | Tree_Handle -> tid = 0xFFFF; /* Invalid TID */ | |
724 | Tree_Handle -> mbs = 0; /* Invalid */ | |
725 | ||
726 | #ifdef DEBUG | |
727 | ||
728 | fprintf(stderr, "Tree disconnect successful ...\n"); | |
729 | ||
730 | #endif | |
731 | ||
732 | /* What about the tree handle ? */ | |
733 | ||
734 | if (discard == TRUE) { /* Unlink it and free it ... */ | |
735 | ||
736 | if (Tree_Handle -> next == NULL) | |
737 | Tree_Handle -> con -> first_tree = Tree_Handle -> prev; | |
738 | else | |
739 | Tree_Handle -> next -> prev = Tree_Handle -> prev; | |
740 | ||
741 | if (Tree_Handle -> prev == NULL) | |
742 | Tree_Handle -> con -> last_tree = Tree_Handle -> next; | |
743 | else | |
744 | Tree_Handle -> prev -> next = Tree_Handle -> next; | |
745 | ||
746 | } | |
747 | ||
748 | RFCNB_Free_Pkt(pkt); | |
749 | return(0); | |
750 | ||
751 | } | |
752 | ||
753 | /* Pick up the last LMBlib error ... */ | |
754 | ||
755 | int SMB_Get_Last_Error() | |
756 | ||
757 | { | |
758 | ||
759 | return(SMBlib_errno); | |
760 | ||
761 | } | |
762 | ||
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 | ||
768 | { | |
769 | ||
770 | return(SMBlib_SMB_Error); | |
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 | ||
778 | static const char *SMBlib_Error_Messages[] = { | |
779 | ||
780 | "Request completed successfully.", | |
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.", | |
793 | /* This next one simplifies error handling */ | |
794 | "No such error code.", | |
795 | NULL | |
796 | }; | |
797 | ||
798 | void SMB_Get_Error_Msg(int msg, char *msgbuf, int len) | |
799 | ||
800 | { | |
801 | ||
802 | if (msg >= 0) { | |
803 | ||
804 | strncpy(msgbuf, | |
805 | SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg], | |
806 | len - 1); | |
807 | msgbuf[len - 1] = 0; /* Make sure it is a string */ | |
808 | } else { /* Add the lower layer message ... */ | |
809 | ||
810 | char prot_msg[1024]; | |
811 | ||
812 | msg = -msg; /* Make it positive */ | |
813 | ||
814 | strncpy(msgbuf, | |
815 | SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg], | |
816 | len - 1); | |
817 | ||
818 | msgbuf[len - 1] = 0; /* make sure it is a string */ | |
819 | ||
820 | if (strlen(msgbuf) < len) { /* If there is space, put rest in */ | |
821 | ||
822 | strncat(msgbuf, "\n\t", len - strlen(msgbuf)); | |
823 | ||
824 | RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1); | |
825 | ||
826 | strncat(msgbuf, prot_msg, len - strlen(msgbuf)); | |
827 | ||
828 | } | |
829 | } | |
830 | ||
831 | } | |
832 |