smblib-util.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 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 
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 
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 
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 */
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",
344 #endif
345 
347  RFCNB_Free_Pkt(pkt);
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);
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);
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