2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
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.
9 /* UNIX SMBlib NetBIOS implementation
14 Copyright (C) Richard Sharpe 1996
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.
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.
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.
39 #include "rfcnb/rfcnb.h"
40 #include "smblib/smblib-priv.h"
41 #include "smblib/smblib.h"
48 SMB_State_Types SMBlib_State
;
50 const char *SMB_Prots
[] = {"PC NETWORK PROGRAM 1.0",
51 "MICROSOFT NETWORKS 1.03",
52 "MICROSOFT NETWORKS 3.0",
65 /* Initialize the SMBlib package */
71 SMBlib_State
= SMB_State_Started
;
73 signal(SIGPIPE
, SIG_IGN
); /* Ignore these ... */
75 /* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
76 #ifdef SMBLIB_INSTRUMENT
78 SMBlib_Instrument_Init();
86 /* SMB_Create: Create a connection structure and return for later use */
87 /* We have other helper routines to set variables */
89 SMB_Handle_Type
SMB_Create_Con_Handle()
93 SMBlib_errno
= SMBlibE_NotImpl
;
98 /* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
99 /* or anything else ... */
101 SMB_Handle_Type
SMB_Connect_Server(SMB_Handle_Type Con_Handle
,
102 const char *server
, const char *NTdomain
)
106 char called
[80], calling
[80], *address
;
109 /* Get a connection structure if one does not exist */
113 if (Con_Handle
== NULL
) {
115 if ((con
= (struct SMB_Connect_Def
*)malloc(sizeof(struct SMB_Connect_Def
))) == NULL
) {
117 SMBlib_errno
= SMBlibE_NoSpace
;
123 /* Init some things ... */
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
;
138 SMB_Get_My_Name(con
-> myname
, sizeof(con
-> myname
));
140 con
-> port
= 0; /* No port selected */
142 /* Get some things we need for the SMB Header */
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();
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 */
152 for (i
=0; i
< strlen(server
); i
++)
153 called
[i
] = xtoupper(server
[i
]);
155 called
[strlen(server
)] = 0; /* Make it a string */
157 for (i
=0; i
< strlen(con
-> myname
); i
++)
158 calling
[i
] = xtoupper(con
-> myname
[i
]);
160 calling
[strlen(con
-> myname
)] = 0; /* Make it a string */
162 if (strlen(con
-> address
) == 0)
163 address
= con
-> desthost
;
165 address
= con
-> address
;
167 con
-> Trans_Connect
= RFCNB_Call(called
,
169 address
, /* Protocol specific */
172 /* Did we get one? */
174 if (con
-> Trans_Connect
== NULL
) {
176 if (Con_Handle
== NULL
) {
180 SMBlib_errno
= -SMBlibE_CallFailed
;
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 */
193 const char *SMB_Prots_Restrict
[] = {"PC NETWORK PROGRAM 1.0",
197 SMB_Handle_Type
SMB_Connect(SMB_Handle_Type Con_Handle
,
198 SMB_Tree_Handle
*tree
,
205 char *host
, *address
;
206 char temp
[80], called
[80], calling
[80];
209 /* Get a connection structure if one does not exist */
213 if (Con_Handle
== NULL
) {
215 if ((con
= (struct SMB_Connect_Def
*)malloc(sizeof(struct SMB_Connect_Def
))) == NULL
) {
217 SMBlib_errno
= SMBlibE_NoSpace
;
223 /* Init some things ... */
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
;
238 SMB_Get_My_Name(con
-> myname
, sizeof(con
-> myname
));
240 con
-> port
= 0; /* No port selected */
242 /* Get some things we need for the SMB Header */
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();
249 /* Now figure out the host portion of the service */
251 strncpy(temp
, service
, sizeof(temp
));
252 temp
[sizeof(temp
) - 1] = '\0';
253 host
= strtok(temp
, "/\\"); /* Separate host name portion */
255 if (Con_Handle
== NULL
) {
259 SMBlib_errno
= -SMBlibE_CallFailed
;
262 strncpy(con
->desthost
, host
, sizeof(con
->desthost
));
263 con
->desthost
[sizeof(con
->desthost
)-1]='\0';
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 */
268 for (i
=0; i
< strlen(host
); i
++)
269 called
[i
] = xtoupper(host
[i
]);
271 called
[strlen(host
)] = 0; /* Make it a string */
273 for (i
=0; i
< strlen(con
-> myname
); i
++)
274 calling
[i
] = xtoupper(con
-> myname
[i
]);
276 calling
[strlen(con
-> myname
)] = 0; /* Make it a string */
278 if (strlen(con
-> address
) == 0)
279 address
= con
-> desthost
;
281 address
= con
-> address
;
283 con
-> Trans_Connect
= RFCNB_Call(called
,
285 address
, /* Protocol specific */
288 /* Did we get one? */
290 if (con
-> Trans_Connect
== NULL
) {
292 if (Con_Handle
== NULL
) {
296 SMBlib_errno
= -SMBlibE_CallFailed
;
301 /* Now, negotiate the protocol */
303 if (SMB_Negotiate(con
, SMB_Prots_Restrict
) < 0) {
305 if (Con_Handle
== NULL
) {
308 SMBlib_errno
= -SMBlibE_NegNoProt
;
313 /* Now connect to the service ... */
315 if ((*tree
= SMB_TreeConnect(con
, NULL
, service
, password
, "A:")) == NULL
) {
317 if (Con_Handle
== NULL
) {
320 SMBlib_errno
= -SMBlibE_BAD
;
329 /* Logon to the server. That is, do a session setup if we can. We do not do */
332 int SMB_Logon_Server(SMB_Handle_Type Con_Handle
, char *UserName
,
333 char *PassWord
, const char *NtDomain
, int PreCrypted
)
336 struct RFCNB_Pkt
*pkt
;
337 int param_len
, pkt_len
, pass_len
;
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 */
344 if (Con_Handle
-> protocol
< SMB_P_LanMan1
) {
346 SMBlib_errno
= SMBlibE_ProtLow
;
353 memcpy(pword
, PassWord
, 24);
355 strncpy(pword
, PassWord
, sizeof(pword
));
356 pword
[sizeof(pword
) - 1] = '\0';
357 #ifdef PAM_SMB_ENC_PASS
358 if (Con_Handle
->encrypt_passwords
) {
360 SMBencrypt((uchar
*) PassWord
, (uchar
*) Con_Handle
->Encrypt_Key
, (uchar
*) pword
);
363 pass_len
= strlen(pword
);
366 /* Now build the correct structure */
368 if (Con_Handle
-> protocol
< SMB_P_NT1
) {
370 /* We don't handle encrypted passwords ... */
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;
376 pkt_len
= SMB_ssetpLM_len
+ param_len
;
378 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
382 SMBlib_errno
= SMBlibE_NoSpace
;
383 return(SMBlibE_BAD
); /* Should handle the error */
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);
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
);
406 /* Now copy the param strings in with the right stuff */
408 p
= (char *)(SMB_Hdr(pkt
) + SMB_ssetpLM_buf_offset
);
410 /* Copy in password, then the rest. Password has a null at end */
412 memcpy(p
, pword
, pass_len
);
414 p
= p
+ pass_len
+ 1;
417 p
= p
+ strlen(UserName
);
422 if (NtDomain
== NULL
) {
423 strcpy(p
, Con_Handle
-> PDomain
);
424 p
= p
+ strlen(Con_Handle
-> PDomain
);
427 p
= p
+ strlen(NtDomain
);
432 strcpy(p
, Con_Handle
-> OSName
);
433 p
= p
+ strlen(Con_Handle
-> OSName
);
438 /* We don't admit to UNICODE support ... */
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;
445 pkt_len
= SMB_ssetpNTLM_len
+ param_len
;
447 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
451 SMBlib_errno
= SMBlibE_NoSpace
;
452 return(-1); /* Should handle the error */
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);
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
);
477 /* Now copy the param strings in with the right stuff */
479 p
= (char *)(SMB_Hdr(pkt
) + SMB_ssetpNTLM_buf_offset
);
481 /* Copy in password, then the rest. Password has no null at end */
483 memcpy(p
, pword
, pass_len
);
488 p
= p
+ strlen(UserName
);
493 strcpy(p
, Con_Handle
-> PDomain
);
494 p
= p
+ strlen(Con_Handle
-> PDomain
);
498 strcpy(p
, Con_Handle
-> OSName
);
499 p
= p
+ strlen(Con_Handle
-> OSName
);
503 strcpy(p
, Con_Handle
-> LMType
);
504 p
= p
+ strlen(Con_Handle
-> LMType
);
509 /* Now send it and get a response */
511 if (RFCNB_Send(Con_Handle
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
514 fprintf(stderr
, "Error sending SessSetupX request\n");
518 SMBlib_errno
= SMBlibE_SendFailed
;
523 /* Now get the response ... */
525 if (RFCNB_Recv(Con_Handle
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
528 fprintf(stderr
, "Error receiving response to SessSetupAndX\n");
532 SMBlib_errno
= SMBlibE_RecvFailed
;
537 /* Check out the response type ... */
539 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
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
));
547 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
549 SMBlib_errno
= SMBlibE_Remote
;
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
);
562 fprintf(stderr
, "SessSetupAndX response. Action = %i\n",
563 SVAL(SMB_Hdr(pkt
), SMB_ssetpr_act_offset
));
566 /* Now pick up the UID for future reference ... */
568 Con_Handle
-> uid
= SVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
);
575 /* Disconnect from the server, and disconnect all tree connects */
577 int SMB_Discon(SMB_Handle_Type Con_Handle
, BOOL KeepHandle
)
581 /* We just disconnect the connection for now ... */
583 RFCNB_Hangup(Con_Handle
-> Trans_Connect
);