]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/smblib/smblib.c
1d82781dd0cf3bc3facc2da44dda900cfeb3e727
[thirdparty/squid.git] / lib / smblib / smblib.c
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 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
35 int SMBlib_errno;
36 int SMBlib_SMB_Error;
37 #define SMBLIB_ERRNO
38
39 #include "rfcnb/rfcnb.h"
40 #include "smblib/smblib-priv.h"
41 #include "smblib/smblib.h"
42
43 #include <signal.h>
44 #if HAVE_STRING_H
45 #include <string.h>
46 #endif
47
48 SMB_State_Types SMBlib_State;
49
50 const char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0",
51 "MICROSOFT NETWORKS 1.03",
52 "MICROSOFT NETWORKS 3.0",
53 "DOS LANMAN1.0",
54 "LANMAN1.0",
55 "DOS LM1.2X002",
56 "LM1.2X002",
57 "DOS LANMAN2.1",
58 "LANMAN2.1",
59 "Samba",
60 "NT LM 0.12",
61 "NT LANMAN 1.0",
62 NULL
63 };
64
65 /* Initialize the SMBlib package */
66
67 int SMB_Init()
68
69 {
70
71 SMBlib_State = SMB_State_Started;
72
73 signal(SIGPIPE, SIG_IGN); /* Ignore these ... */
74
75 /* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
76 #ifdef SMBLIB_INSTRUMENT
77
78 SMBlib_Instrument_Init();
79
80 #endif
81
82 return 0;
83
84 }
85
86 /* SMB_Create: Create a connection structure and return for later use */
87 /* We have other helper routines to set variables */
88
89 SMB_Handle_Type SMB_Create_Con_Handle()
90
91 {
92
93 SMBlib_errno = SMBlibE_NotImpl;
94 return(NULL);
95
96 }
97
98 /* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
99 /* or anything else ... */
100
101 SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
102 const char *server, const char *NTdomain)
103
104 {
105 SMB_Handle_Type con;
106 char called[80], calling[80], *address;
107 int i;
108
109 /* Get a connection structure if one does not exist */
110
111 con = Con_Handle;
112
113 if (Con_Handle == NULL) {
114
115 if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
116
117 SMBlib_errno = SMBlibE_NoSpace;
118 return NULL;
119 }
120
121 }
122
123 /* Init some things ... */
124
125 strcpy(con -> service, "");
126 strcpy(con -> username, "");
127 strcpy(con -> password, "");
128 strcpy(con -> sock_options, "");
129 strcpy(con -> address, "");
130 strncpy(con -> desthost, server, sizeof(con->desthost));
131 con->desthost[sizeof(con->desthost) - 1] = '\0';
132 strncpy(con -> PDomain, NTdomain, sizeof(con->PDomain));
133 con->PDomain[sizeof(con->PDomain) - 1] = '\0';
134 strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME);
135 strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE);
136 con -> first_tree = con -> last_tree = NULL;
137
138 SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
139
140 con -> port = 0; /* No port selected */
141
142 /* Get some things we need for the SMB Header */
143
144 con -> pid = getpid();
145 con -> mid = con -> pid; /* This will do for now ... */
146 con -> uid = 0; /* Until we have done a logon, no uid ... */
147 con -> gid = getgid();
148
149 /* Now connect to the remote end, but first upper case the name of the
150 service we are going to call, sine some servers want it in uppercase */
151
152 for (i=0; i < strlen(con -> desthost); i++)
153 called[i] = xtoupper(con -> desthost[i]);
154
155 called[strlen(con -> desthost)] = 0; /* Make it a string */
156
157 for (i=0; i < strlen(con -> myname); i++)
158 calling[i] = xtoupper(con -> myname[i]);
159
160 calling[strlen(con -> myname)] = 0; /* Make it a string */
161
162 if (strlen(con -> address) == 0)
163 address = con -> desthost;
164 else
165 address = con -> address;
166
167 con -> Trans_Connect = RFCNB_Call(called,
168 calling,
169 address, /* Protocol specific */
170 con -> port);
171
172 /* Did we get one? */
173
174 if (con -> Trans_Connect == NULL) {
175
176 if (Con_Handle == NULL) {
177 Con_Handle = NULL;
178 free(con);
179 }
180 SMBlib_errno = -SMBlibE_CallFailed;
181 return NULL;
182
183 }
184
185 return(con);
186
187 }
188
189 /* SMB_Connect: Connect to the indicated server */
190 /* If Con_Handle == NULL then create a handle and connect, otherwise */
191 /* use the handle passed */
192
193 const char *SMB_Prots_Restrict[] = {"PC NETWORK PROGRAM 1.0",
194 NULL
195 };
196
197 SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle,
198 SMB_Tree_Handle *tree,
199 char *service,
200 char *username,
201 char *password)
202
203 {
204 SMB_Handle_Type con;
205 char *host, *address;
206 char temp[80], called[80], calling[80];
207 int i;
208
209 /* Get a connection structure if one does not exist */
210
211 con = Con_Handle;
212
213 if (Con_Handle == NULL) {
214
215 if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
216
217 SMBlib_errno = SMBlibE_NoSpace;
218 return NULL;
219 }
220
221 }
222
223 /* Init some things ... */
224
225 strncpy(con -> service, service, sizeof(con -> service));
226 con -> service[sizeof(con -> service) - 1] = '\0';
227 strncpy(con -> username, username, sizeof(con -> username));
228 con -> username[sizeof(con -> username) - 1] = '\0';
229 strncpy(con -> password, password, sizeof(con -> password));
230 con -> password[sizeof(con -> password) - 1] = '\0';
231 strcpy(con -> sock_options, "");
232 strcpy(con -> address, "");
233 strcpy(con -> PDomain, SMBLIB_DEFAULT_DOMAIN);
234 strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME);
235 strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE);
236 con -> first_tree = con -> last_tree = NULL;
237
238 SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
239
240 con -> port = 0; /* No port selected */
241
242 /* Get some things we need for the SMB Header */
243
244 con -> pid = getpid();
245 con -> mid = con -> pid; /* This will do for now ... */
246 con -> uid = 0; /* Until we have done a logon, no uid */
247 con -> gid = getgid();
248
249 /* Now figure out the host portion of the service */
250
251 strncpy(temp, service, sizeof(temp));
252 temp[sizeof(temp) - 1] = '\0';
253 host = strtok(temp, "/\\"); /* Separate host name portion */
254 if (!host) {
255 if (Con_Handle == NULL) {
256 free(con);
257 Con_Handle = NULL;
258 }
259 SMBlib_errno = -SMBlibE_CallFailed;
260 return NULL;
261 }
262 strncpy(con->desthost, host, sizeof(con->desthost));
263 con->desthost[sizeof(con->desthost)-1]='\0';
264
265 /* Now connect to the remote end, but first upper case the name of the
266 service we are going to call, sine some servers want it in uppercase */
267
268 for (i=0; i < strlen(con -> desthost); i++)
269 called[i] = xtoupper(con -> desthost[i]);
270
271 called[strlen(con -> desthost)] = 0; /* Make it a string */
272
273 for (i=0; i < strlen(con -> myname); i++)
274 calling[i] = xtoupper(con -> myname[i]);
275
276 calling[strlen(con -> myname)] = 0; /* Make it a string */
277
278 if (strlen(con -> address) == 0)
279 address = con -> desthost;
280 else
281 address = con -> address;
282
283 con -> Trans_Connect = RFCNB_Call(called,
284 calling,
285 address, /* Protocol specific */
286 con -> port);
287
288 /* Did we get one? */
289
290 if (con -> Trans_Connect == NULL) {
291
292 if (Con_Handle == NULL) {
293 free(con);
294 Con_Handle = NULL;
295 }
296 SMBlib_errno = -SMBlibE_CallFailed;
297 return NULL;
298
299 }
300
301 /* Now, negotiate the protocol */
302
303 if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
304
305 if (Con_Handle == NULL) {
306 free(con);
307 }
308 SMBlib_errno = -SMBlibE_NegNoProt;
309 return NULL;
310
311 }
312
313 /* Now connect to the service ... */
314
315 if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
316
317 if (Con_Handle == NULL) {
318 free(con);
319 }
320 SMBlib_errno = -SMBlibE_BAD;
321 return NULL;
322
323 }
324
325 return(con);
326
327 }
328
329 /* Logon to the server. That is, do a session setup if we can. We do not do */
330 /* Unicode yet! */
331
332 int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
333 char *PassWord, const char *NtDomain, int PreCrypted)
334
335 {
336 struct RFCNB_Pkt *pkt;
337 int param_len, pkt_len, pass_len;
338 char *p, pword[128];
339
340 /* First we need a packet etc ... but we need to know what protocol has */
341 /* been negotiated to figure out if we can do it and what SMB format to */
342 /* use ... */
343
344 if (Con_Handle -> protocol < SMB_P_LanMan1) {
345
346 SMBlib_errno = SMBlibE_ProtLow;
347 return(SMBlibE_BAD);
348
349 }
350
351 if (PreCrypted) {
352 pass_len = 24;
353 memcpy(pword, PassWord, 24);
354 } else {
355 strncpy(pword, PassWord, sizeof(pword));
356 pword[sizeof(pword) - 1] = '\0';
357 #ifdef PAM_SMB_ENC_PASS
358 if (Con_Handle->encrypt_passwords) {
359 pass_len = 24;
360 SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
361 } else
362 #endif
363 pass_len = strlen(pword);
364 }
365
366 /* Now build the correct structure */
367
368 if (Con_Handle -> protocol < SMB_P_NT1) {
369
370 /* We don't handle encrypted passwords ... */
371
372 param_len = strlen(UserName) + 1 + pass_len + 1 +
373 (NtDomain!=NULL ? strlen(NtDomain) : strlen(Con_Handle->PDomain)) + 1 +
374 strlen(Con_Handle -> OSName) + 1;
375
376 pkt_len = SMB_ssetpLM_len + param_len;
377
378 pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
379
380 if (pkt == NULL) {
381
382 SMBlib_errno = SMBlibE_NoSpace;
383 return(SMBlibE_BAD); /* Should handle the error */
384
385 }
386
387 memset(SMB_Hdr(pkt), 0, SMB_ssetpLM_len);
388 SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
389 *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
390 SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
391 SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
392 SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
393 SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
394 *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
395 *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
396 SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
397
398 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
399 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
400 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle -> pid);
401 SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
402 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
403 SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
404 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
405
406 /* Now copy the param strings in with the right stuff */
407
408 p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
409
410 /* Copy in password, then the rest. Password has a null at end */
411
412 memcpy(p, pword, pass_len);
413
414 p = p + pass_len + 1;
415
416 strcpy(p, UserName);
417 p = p + strlen(UserName);
418 *p = 0;
419
420 p = p + 1;
421
422 if (NtDomain == NULL) {
423 strcpy(p, Con_Handle -> PDomain);
424 p = p + strlen(Con_Handle -> PDomain);
425 } else {
426 strcpy(p, NtDomain);
427 p = p + strlen(NtDomain);
428 }
429 *p = 0;
430 p = p + 1;
431
432 strcpy(p, Con_Handle -> OSName);
433 p = p + strlen(Con_Handle -> OSName);
434 *p = 0;
435
436 } else {
437
438 /* We don't admit to UNICODE support ... */
439
440 param_len = strlen(UserName) + 1 + pass_len +
441 strlen(Con_Handle -> PDomain) + 1 +
442 strlen(Con_Handle -> OSName) + 1 +
443 strlen(Con_Handle -> LMType) + 1;
444
445 pkt_len = SMB_ssetpNTLM_len + param_len;
446
447 pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
448
449 if (pkt == NULL) {
450
451 SMBlib_errno = SMBlibE_NoSpace;
452 return(-1); /* Should handle the error */
453
454 }
455
456 memset(SMB_Hdr(pkt), 0, SMB_ssetpNTLM_len);
457 SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
458 *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
459 SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
460 SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
461 SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
462 SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
463 *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
464 *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
465 SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
466
467 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
468 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
469 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 1); /* Thanks Tridge! */
470 SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
471 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
472 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
473 SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
474 SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
475 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
476
477 /* Now copy the param strings in with the right stuff */
478
479 p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
480
481 /* Copy in password, then the rest. Password has no null at end */
482
483 memcpy(p, pword, pass_len);
484
485 p = p + pass_len;
486
487 strcpy(p, UserName);
488 p = p + strlen(UserName);
489 *p = 0;
490
491 p = p + 1;
492
493 strcpy(p, Con_Handle -> PDomain);
494 p = p + strlen(Con_Handle -> PDomain);
495 *p = 0;
496 p = p + 1;
497
498 strcpy(p, Con_Handle -> OSName);
499 p = p + strlen(Con_Handle -> OSName);
500 *p = 0;
501 p = p + 1;
502
503 strcpy(p, Con_Handle -> LMType);
504 p = p + strlen(Con_Handle -> LMType);
505 *p = 0;
506
507 }
508
509 /* Now send it and get a response */
510
511 if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
512
513 #ifdef DEBUG
514 fprintf(stderr, "Error sending SessSetupX request\n");
515 #endif
516
517 RFCNB_Free_Pkt(pkt);
518 SMBlib_errno = SMBlibE_SendFailed;
519 return(SMBlibE_BAD);
520
521 }
522
523 /* Now get the response ... */
524
525 if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
526
527 #ifdef DEBUG
528 fprintf(stderr, "Error receiving response to SessSetupAndX\n");
529 #endif
530
531 RFCNB_Free_Pkt(pkt);
532 SMBlib_errno = SMBlibE_RecvFailed;
533 return(SMBlibE_BAD);
534
535 }
536
537 /* Check out the response type ... */
538
539 if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
540
541 #ifdef DEBUG
542 fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
543 CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
544 SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
545 #endif
546
547 SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
548 RFCNB_Free_Pkt(pkt);
549 SMBlib_errno = SMBlibE_Remote;
550 return(SMBlibE_BAD);
551
552 }
553
554 /** @@@ mdz: check for guest login { **/
555 if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1) {
556 /* do we allow guest login? NO! */
557 return (SMBlibE_BAD);
558 }
559 /** @@@ mdz: } **/
560
561 #ifdef DEBUG
562 fprintf(stderr, "SessSetupAndX response. Action = %i\n",
563 SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
564 #endif
565
566 /* Now pick up the UID for future reference ... */
567
568 Con_Handle -> uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
569 RFCNB_Free_Pkt(pkt);
570
571 return(0);
572
573 }
574
575 /* Disconnect from the server, and disconnect all tree connects */
576
577 int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
578
579 {
580
581 /* We just disconnect the connection for now ... */
582
583 RFCNB_Hangup(Con_Handle -> Trans_Connect);
584
585 if (!KeepHandle)
586 free(Con_Handle);
587
588 return(0);
589
590 }
591