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",
58 /* Initialize the SMBlib package */
64 SMBlib_State
= SMB_State_Started
;
66 signal(SIGPIPE
, SIG_IGN
); /* Ignore these ... */
68 /* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
69 #ifdef SMBLIB_INSTRUMENT
71 SMBlib_Instrument_Init();
79 /* SMB_Create: Create a connection structure and return for later use */
80 /* We have other helper routines to set variables */
82 SMB_Handle_Type
SMB_Create_Con_Handle()
86 SMBlib_errno
= SMBlibE_NotImpl
;
91 /* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
92 /* or anything else ... */
94 SMB_Handle_Type
SMB_Connect_Server(SMB_Handle_Type Con_Handle
,
95 char *server
, const char *NTdomain
)
99 char called
[80], calling
[80], *address
;
102 /* Get a connection structure if one does not exist */
106 if (Con_Handle
== NULL
) {
108 if ((con
= (struct SMB_Connect_Def
*)malloc(sizeof(struct SMB_Connect_Def
))) == NULL
) {
110 SMBlib_errno
= SMBlibE_NoSpace
;
116 /* Init some things ... */
118 strcpy(con
-> service
, "");
119 strcpy(con
-> username
, "");
120 strcpy(con
-> password
, "");
121 strcpy(con
-> sock_options
, "");
122 strcpy(con
-> address
, "");
123 strcpy(con
-> desthost
, server
);
124 strcpy(con
-> PDomain
, NTdomain
);
125 strcpy(con
-> OSName
, SMBLIB_DEFAULT_OSNAME
);
126 strcpy(con
-> LMType
, SMBLIB_DEFAULT_LMTYPE
);
127 con
-> first_tree
= con
-> last_tree
= NULL
;
129 SMB_Get_My_Name(con
-> myname
, sizeof(con
-> myname
));
131 con
-> port
= 0; /* No port selected */
133 /* Get some things we need for the SMB Header */
135 con
-> pid
= getpid();
136 con
-> mid
= con
-> pid
; /* This will do for now ... */
137 con
-> uid
= 0; /* Until we have done a logon, no uid ... */
138 con
-> gid
= getgid();
140 /* Now connect to the remote end, but first upper case the name of the
141 service we are going to call, sine some servers want it in uppercase */
143 for (i
=0; i
< strlen(server
); i
++)
144 called
[i
] = toupper(server
[i
]);
146 called
[strlen(server
)] = 0; /* Make it a string */
148 for (i
=0; i
< strlen(con
-> myname
); i
++)
149 calling
[i
] = toupper(con
-> myname
[i
]);
151 calling
[strlen(con
-> myname
)] = 0; /* Make it a string */
153 if (strcmp(con
-> address
, "") == 0)
154 address
= con
-> desthost
;
156 address
= con
-> address
;
158 con
-> Trans_Connect
= RFCNB_Call(called
,
160 address
, /* Protocol specific */
163 /* Did we get one? */
165 if (con
-> Trans_Connect
== NULL
) {
167 if (Con_Handle
== NULL
) {
171 SMBlib_errno
= -SMBlibE_CallFailed
;
180 /* SMB_Connect: Connect to the indicated server */
181 /* If Con_Handle == NULL then create a handle and connect, otherwise */
182 /* use the handle passed */
184 const char *SMB_Prots_Restrict
[] = {"PC NETWORK PROGRAM 1.0",
188 SMB_Handle_Type
SMB_Connect(SMB_Handle_Type Con_Handle
,
189 SMB_Tree_Handle
*tree
,
196 char *host
, *address
;
197 char temp
[80], called
[80], calling
[80];
200 /* Get a connection structure if one does not exist */
204 if (Con_Handle
== NULL
) {
206 if ((con
= (struct SMB_Connect_Def
*)malloc(sizeof(struct SMB_Connect_Def
))) == NULL
) {
208 SMBlib_errno
= SMBlibE_NoSpace
;
214 /* Init some things ... */
216 strcpy(con
-> service
, service
);
217 strcpy(con
-> username
, username
);
218 strcpy(con
-> password
, password
);
219 strcpy(con
-> sock_options
, "");
220 strcpy(con
-> address
, "");
221 strcpy(con
-> PDomain
, SMBLIB_DEFAULT_DOMAIN
);
222 strcpy(con
-> OSName
, SMBLIB_DEFAULT_OSNAME
);
223 strcpy(con
-> LMType
, SMBLIB_DEFAULT_LMTYPE
);
224 con
-> first_tree
= con
-> last_tree
= NULL
;
226 SMB_Get_My_Name(con
-> myname
, sizeof(con
-> myname
));
228 con
-> port
= 0; /* No port selected */
230 /* Get some things we need for the SMB Header */
232 con
-> pid
= getpid();
233 con
-> mid
= con
-> pid
; /* This will do for now ... */
234 con
-> uid
= 0; /* Until we have done a logon, no uid */
235 con
-> gid
= getgid();
237 /* Now figure out the host portion of the service */
239 strcpy(temp
, service
);
240 host
= strtok(temp
, "/\\"); /* Separate host name portion */
241 strcpy(con
-> desthost
, host
);
243 /* Now connect to the remote end, but first upper case the name of the
244 service we are going to call, sine some servers want it in uppercase */
246 for (i
=0; i
< strlen(host
); i
++)
247 called
[i
] = toupper(host
[i
]);
249 called
[strlen(host
)] = 0; /* Make it a string */
251 for (i
=0; i
< strlen(con
-> myname
); i
++)
252 calling
[i
] = toupper(con
-> myname
[i
]);
254 calling
[strlen(con
-> myname
)] = 0; /* Make it a string */
256 if (strcmp(con
-> address
, "") == 0)
257 address
= con
-> desthost
;
259 address
= con
-> address
;
261 con
-> Trans_Connect
= RFCNB_Call(called
,
263 address
, /* Protocol specific */
266 /* Did we get one? */
268 if (con
-> Trans_Connect
== NULL
) {
270 if (Con_Handle
== NULL
) {
274 SMBlib_errno
= -SMBlibE_CallFailed
;
279 /* Now, negotiate the protocol */
281 if (SMB_Negotiate(con
, SMB_Prots_Restrict
) < 0) {
283 /* Hmmm what should we do here ... We have a connection, but could not
290 /* Now connect to the service ... */
292 if ((*tree
= SMB_TreeConnect(con
, NULL
, service
, password
, "A:")) == NULL
) {
302 /* Logon to the server. That is, do a session setup if we can. We do not do */
305 int SMB_Logon_Server(SMB_Handle_Type Con_Handle
, char *UserName
,
306 char *PassWord
, const char *NtDomain
, int PreCrypted
)
309 struct RFCNB_Pkt
*pkt
;
310 int param_len
, pkt_len
, pass_len
;
313 /* First we need a packet etc ... but we need to know what protocol has */
314 /* been negotiated to figure out if we can do it and what SMB format to */
317 if (Con_Handle
-> protocol
< SMB_P_LanMan1
) {
319 SMBlib_errno
= SMBlibE_ProtLow
;
326 memcpy(pword
, PassWord
, 24);
328 strcpy(pword
, PassWord
);
329 #ifdef PAM_SMB_ENC_PASS
330 if (Con_Handle
->encrypt_passwords
) {
332 SMBencrypt((uchar
*) PassWord
, (uchar
*) Con_Handle
->Encrypt_Key
, (uchar
*) pword
);
335 pass_len
= strlen(pword
);
338 /* Now build the correct structure */
340 if (Con_Handle
-> protocol
< SMB_P_NT1
) {
342 /* We don't handle encrypted passwords ... */
344 param_len
= strlen(UserName
) + 1 + pass_len
+ 1 +
345 (NtDomain
!=NULL
? strlen(NtDomain
) : strlen(Con_Handle
->PDomain
)) + 1 +
346 strlen(Con_Handle
-> OSName
) + 1;
348 pkt_len
= SMB_ssetpLM_len
+ param_len
;
350 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
354 SMBlib_errno
= SMBlibE_NoSpace
;
355 return(SMBlibE_BAD
); /* Should handle the error */
359 memset(SMB_Hdr(pkt
), 0, SMB_ssetpLM_len
);
360 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
361 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBsesssetupX
;
362 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, Con_Handle
-> pid
);
363 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, 0);
364 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, Con_Handle
-> mid
);
365 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, Con_Handle
-> uid
);
366 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 10;
367 *(SMB_Hdr(pkt
) + SMB_hdr_axc_offset
) = 0xFF; /* No extra command */
368 SSVAL(SMB_Hdr(pkt
), SMB_hdr_axo_offset
, 0);
370 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_mbs_offset
, SMBLIB_MAX_XMIT
);
371 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_mmc_offset
, 2);
372 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_vcn_offset
, Con_Handle
-> pid
);
373 SIVAL(SMB_Hdr(pkt
), SMB_ssetpLM_snk_offset
, 0);
374 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_pwl_offset
, pass_len
+ 1);
375 SIVAL(SMB_Hdr(pkt
), SMB_ssetpLM_res_offset
, 0);
376 SSVAL(SMB_Hdr(pkt
), SMB_ssetpLM_bcc_offset
, param_len
);
378 /* Now copy the param strings in with the right stuff */
380 p
= (char *)(SMB_Hdr(pkt
) + SMB_ssetpLM_buf_offset
);
382 /* Copy in password, then the rest. Password has a null at end */
384 memcpy(p
, pword
, pass_len
);
386 p
= p
+ pass_len
+ 1;
389 p
= p
+ strlen(UserName
);
394 if (NtDomain
!= NULL
) {
395 strcpy(p
, Con_Handle
-> PDomain
);
396 p
= p
+ strlen(Con_Handle
-> PDomain
);
399 p
= p
+ strlen(NtDomain
);
404 strcpy(p
, Con_Handle
-> OSName
);
405 p
= p
+ strlen(Con_Handle
-> OSName
);
410 /* We don't admit to UNICODE support ... */
412 param_len
= strlen(UserName
) + 1 + pass_len
+
413 strlen(Con_Handle
-> PDomain
) + 1 +
414 strlen(Con_Handle
-> OSName
) + 1 +
415 strlen(Con_Handle
-> LMType
) + 1;
417 pkt_len
= SMB_ssetpNTLM_len
+ param_len
;
419 pkt
= (struct RFCNB_Pkt
*)RFCNB_Alloc_Pkt(pkt_len
);
423 SMBlib_errno
= SMBlibE_NoSpace
;
424 return(-1); /* Should handle the error */
428 memset(SMB_Hdr(pkt
), 0, SMB_ssetpNTLM_len
);
429 SIVAL(SMB_Hdr(pkt
), SMB_hdr_idf_offset
, SMB_DEF_IDF
); /* Plunk in IDF */
430 *(SMB_Hdr(pkt
) + SMB_hdr_com_offset
) = SMBsesssetupX
;
431 SSVAL(SMB_Hdr(pkt
), SMB_hdr_pid_offset
, Con_Handle
-> pid
);
432 SSVAL(SMB_Hdr(pkt
), SMB_hdr_tid_offset
, 0);
433 SSVAL(SMB_Hdr(pkt
), SMB_hdr_mid_offset
, Con_Handle
-> mid
);
434 SSVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
, Con_Handle
-> uid
);
435 *(SMB_Hdr(pkt
) + SMB_hdr_wct_offset
) = 13;
436 *(SMB_Hdr(pkt
) + SMB_hdr_axc_offset
) = 0xFF; /* No extra command */
437 SSVAL(SMB_Hdr(pkt
), SMB_hdr_axo_offset
, 0);
439 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_mbs_offset
, SMBLIB_MAX_XMIT
);
440 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_mmc_offset
, 0);
441 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_vcn_offset
, 1); /* Thanks Tridge! */
442 SIVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_snk_offset
, 0);
443 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_cipl_offset
, pass_len
);
444 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_cspl_offset
, 0);
445 SIVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_res_offset
, 0);
446 SIVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_cap_offset
, 0);
447 SSVAL(SMB_Hdr(pkt
), SMB_ssetpNTLM_bcc_offset
, param_len
);
449 /* Now copy the param strings in with the right stuff */
451 p
= (char *)(SMB_Hdr(pkt
) + SMB_ssetpNTLM_buf_offset
);
453 /* Copy in password, then the rest. Password has no null at end */
455 memcpy(p
, pword
, pass_len
);
460 p
= p
+ strlen(UserName
);
465 strcpy(p
, Con_Handle
-> PDomain
);
466 p
= p
+ strlen(Con_Handle
-> PDomain
);
470 strcpy(p
, Con_Handle
-> OSName
);
471 p
= p
+ strlen(Con_Handle
-> OSName
);
475 strcpy(p
, Con_Handle
-> LMType
);
476 p
= p
+ strlen(Con_Handle
-> LMType
);
481 /* Now send it and get a response */
483 if (RFCNB_Send(Con_Handle
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
486 fprintf(stderr
, "Error sending SessSetupX request\n");
490 SMBlib_errno
= SMBlibE_SendFailed
;
495 /* Now get the response ... */
497 if (RFCNB_Recv(Con_Handle
-> Trans_Connect
, pkt
, pkt_len
) < 0) {
500 fprintf(stderr
, "Error receiving response to SessSetupAndX\n");
504 SMBlib_errno
= SMBlibE_RecvFailed
;
509 /* Check out the response type ... */
511 if (CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
) != SMBC_SUCCESS
) { /* Process error */
514 fprintf(stderr
, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
515 CVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
),
516 SVAL(SMB_Hdr(pkt
), SMB_hdr_err_offset
));
519 SMBlib_SMB_Error
= IVAL(SMB_Hdr(pkt
), SMB_hdr_rcls_offset
);
521 SMBlib_errno
= SMBlibE_Remote
;
526 /** @@@ mdz: check for guest login { **/
527 if (SVAL(SMB_Hdr(pkt
), SMB_ssetpr_act_offset
) & 0x1) {
528 /* do we allow guest login? NO! */
529 return (SMBlibE_BAD
);
534 fprintf(stderr
, "SessSetupAndX response. Action = %i\n",
535 SVAL(SMB_Hdr(pkt
), SMB_ssetpr_act_offset
));
538 /* Now pick up the UID for future reference ... */
540 Con_Handle
-> uid
= SVAL(SMB_Hdr(pkt
), SMB_hdr_uid_offset
);
547 /* Disconnect from the server, and disconnect all tree connects */
549 int SMB_Discon(SMB_Handle_Type Con_Handle
, BOOL KeepHandle
)
553 /* We just disconnect the connection for now ... */
555 RFCNB_Hangup(Con_Handle
-> Trans_Connect
);