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