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