3 /* UNIX SMBlib NetBIOS implementation
8 Copyright (C) Richard Sharpe 1996
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 #include "smblib/smblib.h"
33 #include "smblib/smblib-priv.h"
34 #include "rfcnb/rfcnb.h"
41 SMB_State_Types SMBlib_State
;
43 const char *SMB_Prots
[] = {"PC NETWORK PROGRAM 1.0",
44 "MICROSOFT NETWORKS 1.03",
45 "MICROSOFT NETWORKS 3.0",
59 /* Initialize the SMBlib package */
65 SMBlib_State
= SMB_State_Started
;
67 signal(SIGPIPE
, SIG_IGN
); /* Ignore these ... */
69 /* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
70 #ifdef SMBLIB_INSTRUMENT
72 SMBlib_Instrument_Init();
80 /* SMB_Create: Create a connection structure and return for later use */
81 /* We have other helper routines to set variables */
83 SMB_Handle_Type
SMB_Create_Con_Handle()
87 SMBlib_errno
= SMBlibE_NotImpl
;
92 /* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
93 /* or anything else ... */
95 SMB_Handle_Type
SMB_Connect_Server(SMB_Handle_Type Con_Handle
,
96 char *server
, const char *NTdomain
)
100 char called
[80], calling
[80], *address
;
103 /* Get a connection structure if one does not exist */
107 if (Con_Handle
== NULL
) {
109 if ((con
= (struct SMB_Connect_Def
*)malloc(sizeof(struct SMB_Connect_Def
))) == NULL
) {
112 SMBlib_errno
= SMBlibE_NoSpace
;
118 /* Init some things ... */
120 strcpy(con
-> service
, "");
121 strcpy(con
-> username
, "");
122 strcpy(con
-> password
, "");
123 strcpy(con
-> sock_options
, "");
124 strcpy(con
-> address
, "");
125 strcpy(con
-> desthost
, server
);
126 strcpy(con
-> PDomain
, NTdomain
);
127 strcpy(con
-> OSName
, SMBLIB_DEFAULT_OSNAME
);
128 strcpy(con
-> LMType
, SMBLIB_DEFAULT_LMTYPE
);
129 con
-> first_tree
= con
-> last_tree
= NULL
;
131 SMB_Get_My_Name(con
-> myname
, sizeof(con
-> myname
));
133 con
-> port
= 0; /* No port selected */
135 /* Get some things we need for the SMB Header */
137 con
-> pid
= getpid();
138 con
-> mid
= con
-> pid
; /* This will do for now ... */
139 con
-> uid
= 0; /* Until we have done a logon, no uid ... */
140 con
-> gid
= getgid();
142 /* Now connect to the remote end, but first upper case the name of the
143 service we are going to call, sine some servers want it in uppercase */
145 for (i
=0; i
< strlen(server
); i
++)
146 called
[i
] = toupper(server
[i
]);
148 called
[strlen(server
)] = 0; /* Make it a string */
150 for (i
=0; i
< strlen(con
-> myname
); i
++)
151 calling
[i
] = toupper(con
-> myname
[i
]);
153 calling
[strlen(con
-> myname
)] = 0; /* Make it a string */
155 if (strcmp(con
-> address
, "") == 0)
156 address
= con
-> desthost
;
158 address
= con
-> address
;
160 con
-> Trans_Connect
= RFCNB_Call(called
,
162 address
, /* Protocol specific */
165 /* Did we get one? */
167 if (con
-> Trans_Connect
== NULL
) {
169 if (Con_Handle
== NULL
) {
173 SMBlib_errno
= -SMBlibE_CallFailed
;
182 /* SMB_Connect: Connect to the indicated server */
183 /* If Con_Handle == NULL then create a handle and connect, otherwise */
184 /* use the handle passed */
186 const char *SMB_Prots_Restrict
[] = {"PC NETWORK PROGRAM 1.0",
191 SMB_Handle_Type
SMB_Connect(SMB_Handle_Type Con_Handle
,
192 SMB_Tree_Handle
*tree
,
199 char *host
, *address
;
200 char temp
[80], called
[80], calling
[80];
203 /* Get a connection structure if one does not exist */
207 if (Con_Handle
== NULL
) {
209 if ((con
= (struct SMB_Connect_Def
*)malloc(sizeof(struct SMB_Connect_Def
))) == NULL
) {
211 SMBlib_errno
= SMBlibE_NoSpace
;
217 /* Init some things ... */
219 strcpy(con
-> service
, service
);
220 strcpy(con
-> username
, username
);
221 strcpy(con
-> password
, password
);
222 strcpy(con
-> sock_options
, "");
223 strcpy(con
-> address
, "");
224 strcpy(con
-> PDomain
, SMBLIB_DEFAULT_DOMAIN
);
225 strcpy(con
-> OSName
, SMBLIB_DEFAULT_OSNAME
);
226 strcpy(con
-> LMType
, SMBLIB_DEFAULT_LMTYPE
);
227 con
-> first_tree
= con
-> last_tree
= NULL
;
229 SMB_Get_My_Name(con
-> myname
, sizeof(con
-> myname
));
231 con
-> port
= 0; /* No port selected */
233 /* Get some things we need for the SMB Header */
235 con
-> pid
= getpid();
236 con
-> mid
= con
-> pid
; /* This will do for now ... */
237 con
-> uid
= 0; /* Until we have done a logon, no uid */
238 con
-> gid
= getgid();
240 /* Now figure out the host portion of the service */
242 strcpy(temp
, service
);
243 host
= strtok(temp
, "/\\"); /* Separate host name portion */
244 strcpy(con
-> desthost
, host
);
246 /* Now connect to the remote end, but first upper case the name of the
247 service we are going to call, sine some servers want it in uppercase */
249 for (i
=0; i
< strlen(host
); i
++)
250 called
[i
] = toupper(host
[i
]);
252 called
[strlen(host
)] = 0; /* Make it a string */
254 for (i
=0; i
< strlen(con
-> myname
); i
++)
255 calling
[i
] = toupper(con
-> myname
[i
]);
257 calling
[strlen(con
-> myname
)] = 0; /* Make it a string */
259 if (strcmp(con
-> address
, "") == 0)
260 address
= con
-> desthost
;
262 address
= con
-> address
;
264 con
-> Trans_Connect
= RFCNB_Call(called
,
266 address
, /* Protocol specific */
269 /* Did we get one? */
271 if (con
-> Trans_Connect
== NULL
) {
273 if (Con_Handle
== NULL
) {
277 SMBlib_errno
= -SMBlibE_CallFailed
;
282 /* Now, negotiate the protocol */
284 if (SMB_Negotiate(con
, SMB_Prots_Restrict
) < 0) {
286 /* Hmmm what should we do here ... We have a connection, but could not
293 /* Now connect to the service ... */
295 if ((*tree
= SMB_TreeConnect(con
, NULL
, service
, password
, "A:")) == NULL
) {
305 /* Logon to the server. That is, do a session setup if we can. We do not do */
308 int SMB_Logon_Server(SMB_Handle_Type Con_Handle
, char *UserName
,
309 char *PassWord
, const char *NtDomain
, int PreCrypted
)
312 struct RFCNB_Pkt
*pkt
;
313 int param_len
, pkt_len
, pass_len
;
316 /* First we need a packet etc ... but we need to know what protocol has */
317 /* been negotiated to figure out if we can do it and what SMB format to */
320 if (Con_Handle
-> protocol
< SMB_P_LanMan1
) {
322 SMBlib_errno
= SMBlibE_ProtLow
;
329 memcpy(pword
, PassWord
, 24);
331 strcpy(pword
, PassWord
);
332 #ifdef PAM_SMB_ENC_PASS
333 if (Con_Handle
->encrypt_passwords
) {
335 SMBencrypt((uchar
*) PassWord
, (uchar
*) Con_Handle
->Encrypt_Key
, (uchar
*) pword
);
338 pass_len
= strlen(pword
);
341 /* Now build the correct structure */
343 if (Con_Handle
-> protocol
< SMB_P_NT1
) {
345 /* We don't handle encrypted passwords ... */
347 param_len
= strlen(UserName
) + 1 + pass_len
+ 1 +
348 (NtDomain
!=NULL
? strlen(NtDomain
) : strlen(Con_Handle
->PDomain
)) + 1 +
349 strlen(Con_Handle
-> OSName
) + 1;
351 pkt_len
= SMB_ssetpLM_len
+ param_len
;
353 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
357 SMBlib_errno
= SMBlibE_NoSpace
;
358 return(SMBlibE_BAD
); /* Should handle the error */
362 memset(SMB_Hdr(pkt
), 0, SMB_ssetpLM_len
);
363 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
364 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBsesssetupX
;
365 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, Con_Handle
-> pid
);
366 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, 0);
367 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, Con_Handle
-> mid
);
368 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, Con_Handle
-> uid
);
369 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 10;
370 *(SMB_Hdr(pkt
) + SMB_hdr_axc_offset
) = 0xFF; /* No extra command */
371 SSVAL(SMB_Hdr(pkt
), SMB_hdr_axo_offset
, 0);
373 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_mbs_offset
, SMBLIB_MAX_XMIT
);
374 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_mmc_offset
, 2);
375 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_vcn_offset
, Con_Handle
-> pid
);
376 SIVAL(SMB_Hdr(pkt
), SMB_ssetpLM_snk_offset
, 0);
377 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_pwl_offset
, pass_len
+ 1);
378 SIVAL(SMB_Hdr(pkt
), SMB_ssetpLM_res_offset
, 0);
379 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_bcc_offset
, param_len
);
381 /* Now copy the param strings in with the right stuff */
383 p
= (char *)(SMB_Hdr(pkt
) + SMB_ssetpLM_buf_offset
);
385 /* Copy in password, then the rest. Password has a null at end */
387 memcpy(p
, pword
, pass_len
);
389 p
= p
+ pass_len
+ 1;
392 p
= p
+ strlen(UserName
);
397 if (NtDomain
!= NULL
) {
398 strcpy(p
, Con_Handle
-> PDomain
);
399 p
= p
+ strlen(Con_Handle
-> PDomain
);
402 p
= p
+ strlen(NtDomain
);
407 strcpy(p
, Con_Handle
-> OSName
);
408 p
= p
+ strlen(Con_Handle
-> OSName
);
413 /* We don't admit to UNICODE support ... */
415 param_len
= strlen(UserName
) + 1 + pass_len
+
416 strlen(Con_Handle
-> PDomain
) + 1 +
417 strlen(Con_Handle
-> OSName
) + 1 +
418 strlen(Con_Handle
-> LMType
) + 1;
420 pkt_len
= SMB_ssetpNTLM_len
+ param_len
;
422 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
426 SMBlib_errno
= SMBlibE_NoSpace
;
427 return(-1); /* Should handle the error */
431 memset(SMB_Hdr(pkt
), 0, SMB_ssetpNTLM_len
);
432 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
433 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBsesssetupX
;
434 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, Con_Handle
-> pid
);
435 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, 0);
436 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, Con_Handle
-> mid
);
437 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, Con_Handle
-> uid
);
438 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 13;
439 *(SMB_Hdr(pkt
) + SMB_hdr_axc_offset
) = 0xFF; /* No extra command */
440 SSVAL(SMB_Hdr(pkt
), SMB_hdr_axo_offset
, 0);
442 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_mbs_offset
, SMBLIB_MAX_XMIT
);
443 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_mmc_offset
, 0);
444 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_vcn_offset
, 1); /* Thanks Tridge! */
445 SIVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_snk_offset
, 0);
446 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_cipl_offset
, pass_len
);
447 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_cspl_offset
, 0);
448 SIVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_res_offset
, 0);
449 SIVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_cap_offset
, 0);
450 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_bcc_offset
, param_len
);
452 /* Now copy the param strings in with the right stuff */
454 p
= (char *)(SMB_Hdr(pkt
) + SMB_ssetpNTLM_buf_offset
);
456 /* Copy in password, then the rest. Password has no null at end */
458 memcpy(p
, pword
, pass_len
);
463 p
= p
+ strlen(UserName
);
468 strcpy(p
, Con_Handle
-> PDomain
);
469 p
= p
+ strlen(Con_Handle
-> PDomain
);
473 strcpy(p
, Con_Handle
-> OSName
);
474 p
= p
+ strlen(Con_Handle
-> OSName
);
478 strcpy(p
, Con_Handle
-> LMType
);
479 p
= p
+ strlen(Con_Handle
-> LMType
);
484 /* Now send it and get a response */
486 if (RFCNB_Send(Con_Handle
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
489 fprintf(stderr
, "Error sending SessSetupX request\n");
493 SMBlib_errno
= SMBlibE_SendFailed
;
498 /* Now get the response ... */
500 if (RFCNB_Recv(Con_Handle
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
503 fprintf(stderr
, "Error receiving response to SessSetupAndX\n");
507 SMBlib_errno
= SMBlibE_RecvFailed
;
512 /* Check out the response type ... */
514 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
517 fprintf(stderr
, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
518 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
519 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
522 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
524 SMBlib_errno
= SMBlibE_Remote
;
529 /** @@@ mdz: check for guest login { **/
530 if (SVAL(SMB_Hdr(pkt
), SMB_ssetpr_act_offset
) & 0x1) {
531 /* do we allow guest login? NO! */
532 return (SMBlibE_BAD
);
537 fprintf(stderr
, "SessSetupAndX response. Action = %i\n",
538 SVAL(SMB_Hdr(pkt
), SMB_ssetpr_act_offset
));
541 /* Now pick up the UID for future reference ... */
543 Con_Handle
-> uid
= SVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
);
551 /* Disconnect from the server, and disconnect all tree connects */
553 int SMB_Discon(SMB_Handle_Type Con_Handle
, BOOL KeepHandle
)
557 /* We just disconnect the connection for now ... */
559 RFCNB_Hangup(Con_Handle
-> Trans_Connect
);