2
/* UNIX SMBlib NetBIOS implementation
7
* Copyright (C) Richard Sharpe 1996
12
* This program is free software; you can redistribute it and/or modify
13
* it under the terms of the GNU General Public License as published by
14
* the Free Software Foundation; either version 2 of the License, or
15
* (at your option) any later version.
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU General Public License for more details.
22
* You should have received a copy of the GNU General Public License
23
* along with this program; if not, write to the Free Software
24
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35
#define uchar unsigned char
36
#include "smblib-priv.h"
39
#include "smbencrypt.h"
45
SMB_State_Types SMBlib_State;
47
/* Initialize the SMBlib package */
53
SMBlib_State = SMB_State_Started;
55
signal(SIGPIPE, SIG_IGN); /* Ignore these ... */
57
/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
58
#ifdef SMBLIB_INSTRUMENT
60
SMBlib_Instrument_Init();
72
#ifdef SMBLIB_INSTRUMENT
74
SMBlib_Instrument_Term(); /* Clean up and print results */
82
/* SMB_Create: Create a connection structure and return for later use */
83
/* We have other helper routines to set variables */
86
SMB_Create_Con_Handle()
89
SMBlib_errno = SMBlibE_NotImpl;
95
SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
99
if (RFCNB_Set_Sock_NoDelay(Con_Handle->Trans_Connect, yn) < 0) {
104
fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
111
/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
112
/* or anything else ... */
115
SMB_Connect_Server(SMB_Handle_Type Con_Handle,
116
char *server, char *NTdomain)
119
char called[80], calling[80], *address;
122
/* Get a connection structure if one does not exist */
126
if (Con_Handle == NULL) {
128
if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
131
SMBlib_errno = SMBlibE_NoSpace;
135
/* Init some things ... */
137
strcpy(con->service, "");
138
strcpy(con->username, "");
139
strcpy(con->password, "");
140
strcpy(con->sock_options, "");
141
strcpy(con->address, "");
142
strcpy(con->desthost, server);
143
strcpy(con->PDomain, NTdomain);
144
strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
145
strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
146
con->first_tree = con->last_tree = NULL;
148
/* ugh. This is horribly broken. */
149
/* SMB_Get_My_Name(con -> myname, sizeof(con -> myname)); */
150
/* hacked by Kinkie */
151
i = gethostname(con->myname, sizeof(con->myname));
153
strcpy(con->myname, "unknown");
155
if (NULL != (address = strchr(con->myname, '.'))) {
156
*address = '\0'; /* truncate at first '.' */
161
con->port = 0; /* No port selected */
163
/* Get some things we need for the SMB Header */
166
con->mid = con->pid; /* This will do for now ... */
167
con->uid = 0; /* Until we have done a logon, no uid ... */
170
/* Now connect to the remote end, but first upper case the name of the
171
* service we are going to call, sine some servers want it in uppercase */
173
for (i = 0; i < strlen(server); i++)
174
called[i] = xtoupper(server[i]);
176
called[strlen(server)] = 0; /* Make it a string */
178
for (i = 0; i < strlen(con->myname); i++)
179
calling[i] = xtoupper(con->myname[i]);
181
calling[strlen(con->myname)] = 0; /* Make it a string */
183
if (strcmp(con->address, "") == 0)
184
address = con->desthost;
186
address = con->address;
188
con->Trans_Connect = RFCNB_Call(called,
190
address, /* Protocol specific */
193
/* Did we get one? */
195
if (con->Trans_Connect == NULL) {
197
if (Con_Handle == NULL) {
201
SMBlib_errno = -SMBlibE_CallFailed;
209
/* SMB_Connect: Connect to the indicated server */
210
/* If Con_Handle == NULL then create a handle and connect, otherwise */
211
/* use the handle passed */
213
char *SMB_Prots_Restrict[] =
214
{"PC NETWORK PROGRAM 1.0",
219
SMB_Connect(SMB_Handle_Type Con_Handle,
220
SMB_Tree_Handle * tree,
226
char *host, *address;
227
char temp[80], called[80], calling[80];
230
/* Get a connection structure if one does not exist */
234
if (Con_Handle == NULL) {
236
if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
238
SMBlib_errno = SMBlibE_NoSpace;
242
/* Init some things ... */
244
strcpy(con->service, service);
245
strcpy(con->username, username);
246
strcpy(con->password, password);
247
strcpy(con->sock_options, "");
248
strcpy(con->address, "");
249
strcpy(con->PDomain, SMBLIB_DEFAULT_DOMAIN);
250
strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
251
strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
252
con->first_tree = con->last_tree = NULL;
254
SMB_Get_My_Name(con->myname, sizeof(con->myname));
256
con->port = 0; /* No port selected */
258
/* Get some things we need for the SMB Header */
261
con->mid = con->pid; /* This will do for now ... */
262
con->uid = 0; /* Until we have done a logon, no uid */
265
/* Now figure out the host portion of the service */
267
strcpy(temp, service);
268
host = (char *) strtok(temp, "/\\"); /* Separate host name portion */
269
strcpy(con->desthost, host);
271
/* Now connect to the remote end, but first upper case the name of the
272
* service we are going to call, sine some servers want it in uppercase */
274
for (i = 0; i < strlen(host); i++)
275
called[i] = xtoupper(host[i]);
277
called[strlen(host)] = 0; /* Make it a string */
279
for (i = 0; i < strlen(con->myname); i++)
280
calling[i] = xtoupper(con->myname[i]);
282
calling[strlen(con->myname)] = 0; /* Make it a string */
284
if (strcmp(con->address, "") == 0)
285
address = con->desthost;
287
address = con->address;
289
con->Trans_Connect = RFCNB_Call(called,
291
address, /* Protocol specific */
294
/* Did we get one? */
296
if (con->Trans_Connect == NULL) {
298
if (Con_Handle == NULL) {
302
SMBlib_errno = -SMBlibE_CallFailed;
306
/* Now, negotiate the protocol */
308
if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
310
/* Hmmm what should we do here ... We have a connection, but could not
316
/* Now connect to the service ... */
318
if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
327
/* Logon to the server. That is, do a session setup if we can. We do not do */
331
SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
332
char *PassWord, char *UserDomain, int precrypted)
334
struct RFCNB_Pkt *pkt;
335
int param_len, pkt_len, pass_len;
338
/* First we need a packet etc ... but we need to know what protocol has */
339
/* been negotiated to figure out if we can do it and what SMB format to */
342
if (Con_Handle->protocol < SMB_P_LanMan1) {
344
SMBlib_errno = SMBlibE_ProtLow;
345
return (SMBlibE_BAD);
350
memcpy(pword, PassWord, 24);
352
strcpy(pword, PassWord);
353
if (Con_Handle->encrypt_passwords) {
355
SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
357
pass_len = strlen(pword);
360
/* Now build the correct structure */
362
if (Con_Handle->protocol < SMB_P_NT1) {
364
param_len = strlen(UserName) + 1 + pass_len + 1 +
365
strlen(UserDomain) + 1 +
366
strlen(Con_Handle->OSName) + 1;
368
pkt_len = SMB_ssetpLM_len + param_len;
370
pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
374
SMBlib_errno = SMBlibE_NoSpace;
375
fprintf(stderr, "SMB_Logon_server: Couldn't allocate packet\n");
376
return (SMBlibE_BAD); /* Should handle the error */
378
memset(SMB_Hdr(pkt), 0, SMB_ssetpLM_len);
379
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
380
*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
381
SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
382
SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
383
SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
384
SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
385
*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
386
*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
387
SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
389
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
390
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
391
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle->pid);
392
SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
393
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
394
SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
395
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
397
/* Now copy the param strings in with the right stuff */
399
p = (char *) (SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
401
/* Copy in password, then the rest. Password has a null at end */
403
memcpy(p, pword, pass_len);
405
p = p + pass_len + 1;
408
p = p + strlen(UserName);
413
strcpy(p, UserDomain);
414
p = p + strlen(UserDomain);
418
strcpy(p, Con_Handle->OSName);
419
p = p + strlen(Con_Handle->OSName);
424
/* We don't admit to UNICODE support ... */
426
param_len = strlen(UserName) + 1 + pass_len +
427
strlen(UserDomain) + 1 +
428
strlen(Con_Handle->OSName) + 1 +
429
strlen(Con_Handle->LMType) + 1;
431
pkt_len = SMB_ssetpNTLM_len + param_len;
433
pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
437
SMBlib_errno = SMBlibE_NoSpace;
438
fprintf(stderr, "SMB_Logon_server: Couldn't allocate packet\n");
439
return (-1); /* Should handle the error */
441
memset(SMB_Hdr(pkt), 0, SMB_ssetpNTLM_len);
442
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
443
*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
444
SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
445
SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
446
SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
447
SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
448
*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
449
*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
450
SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
452
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
453
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
454
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 1); /* Thanks Tridge! */
455
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
456
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
457
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
458
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
459
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
460
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
462
/* Now copy the param strings in with the right stuff */
464
p = (char *) (SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
466
/* Copy in password, then the rest. Password has no null at end */
468
memcpy(p, pword, pass_len);
473
p = p + strlen(UserName);
478
strcpy(p, UserDomain);
479
p = p + strlen(UserDomain);
483
strcpy(p, Con_Handle->OSName);
484
p = p + strlen(Con_Handle->OSName);
488
strcpy(p, Con_Handle->LMType);
489
p = p + strlen(Con_Handle->LMType);
494
/* Now send it and get a response */
496
if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
499
fprintf(stderr, "Error sending SessSetupX request\n");
503
SMBlib_errno = SMBlibE_SendFailed;
504
return (SMBlibE_BAD);
507
/* Now get the response ... */
509
if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
512
fprintf(stderr, "Error receiving response to SessSetupAndX\n");
516
SMBlib_errno = SMBlibE_RecvFailed;
517
return (SMBlibE_BAD);
520
/* Check out the response type ... */
522
if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
525
fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
526
CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
527
SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
530
SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
532
SMBlib_errno = SMBlibE_Remote;
533
return (SMBlibE_BAD);
536
/** @@@ mdz: check for guest login { **/
537
if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1) {
538
/* do we allow guest login? NO! */
539
return (SMBlibE_BAD);
546
fprintf(stderr, "SessSetupAndX response. Action = %i\n",
547
SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
550
/* Now pick up the UID for future reference ... */
552
Con_Handle->uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
560
/* Disconnect from the server, and disconnect all tree connects */
563
SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
566
/* We just disconnect the connection for now ... */
567
if (Con_Handle != NULL)
568
RFCNB_Hangup(Con_Handle->Trans_Connect);