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_Handle_Type SMB_Create_Con_Handle(void);
46
int SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn);
47
SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle, char *server, char *NTdomain);
48
SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle, SMB_Tree_Handle * tree, char *service, char *username, char *password);
53
SMB_State_Types SMBlib_State;
55
/* Initialize the SMBlib package */
61
SMBlib_State = SMB_State_Started;
63
signal(SIGPIPE, SIG_IGN); /* Ignore these ... */
65
/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
66
#ifdef SMBLIB_INSTRUMENT
68
SMBlib_Instrument_Init();
80
#ifdef SMBLIB_INSTRUMENT
82
SMBlib_Instrument_Term(); /* Clean up and print results */
91
* SMB_Create: Create a connection structure and return for later use
92
* We have other helper routines to set variables
95
SMB_Create_Con_Handle()
97
SMBlib_errno = SMBlibE_NotImpl;
102
SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
104
if (RFCNB_Set_Sock_NoDelay(Con_Handle->Trans_Connect, yn) < 0) {
105
fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
110
/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
111
/* or anything else ... */
113
SMB_Connect_Server(SMB_Handle_Type Con_Handle,
114
char *server, char *NTdomain)
117
char called[80], calling[80], *address;
120
/* Get a connection structure if one does not exist */
124
if (Con_Handle == NULL) {
126
if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
129
SMBlib_errno = SMBlibE_NoSpace;
133
/* Init some things ... */
135
strcpy(con->service, "");
136
strcpy(con->username, "");
137
strcpy(con->password, "");
138
strcpy(con->sock_options, "");
139
strcpy(con->address, "");
140
strcpy(con->desthost, server);
141
strcpy(con->PDomain, NTdomain);
142
strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
143
strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
144
con->first_tree = con->last_tree = NULL;
146
/* ugh. This is horribly broken. */
147
/* SMB_Get_My_Name(con -> myname, sizeof(con -> myname)); */
148
/* hacked by Kinkie */
149
i = gethostname(con->myname, sizeof(con->myname));
151
strcpy(con->myname, "unknown");
153
if (NULL != (address = strchr(con->myname, '.'))) {
154
*address = '\0'; /* truncate at first '.' */
159
con->port = 0; /* No port selected */
161
/* Get some things we need for the SMB Header */
164
con->mid = con->pid; /* This will do for now ... */
165
con->uid = 0; /* Until we have done a logon, no uid ... */
168
/* Now connect to the remote end, but first upper case the name of the
169
* service we are going to call, sine some servers want it in uppercase */
171
for (i = 0; i < strlen(server); i++)
172
called[i] = xtoupper(server[i]);
174
called[strlen(server)] = 0; /* Make it a string */
176
for (i = 0; i < strlen(con->myname); i++)
177
calling[i] = xtoupper(con->myname[i]);
179
calling[strlen(con->myname)] = 0; /* Make it a string */
181
if (strcmp(con->address, "") == 0)
182
address = con->desthost;
184
address = con->address;
186
con->Trans_Connect = RFCNB_Call(called,
188
address, /* Protocol specific */
191
/* Did we get one? */
193
if (con->Trans_Connect == NULL) {
195
if (Con_Handle == NULL) {
199
SMBlib_errno = -SMBlibE_CallFailed;
207
/* SMB_Connect: Connect to the indicated server */
208
/* If Con_Handle == NULL then create a handle and connect, otherwise */
209
/* use the handle passed */
211
char const *SMB_Prots_Restrict[] = {"PC NETWORK PROGRAM 1.0",
217
SMB_Connect(SMB_Handle_Type Con_Handle,
218
SMB_Tree_Handle * tree,
224
char *host, *address;
225
char temp[80], called[80], calling[80];
228
/* Get a connection structure if one does not exist */
232
if (Con_Handle == NULL) {
234
if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
236
SMBlib_errno = SMBlibE_NoSpace;
240
/* Init some things ... */
242
strcpy(con->service, service);
243
strcpy(con->username, username);
244
strcpy(con->password, password);
245
strcpy(con->sock_options, "");
246
strcpy(con->address, "");
247
strcpy(con->PDomain, SMBLIB_DEFAULT_DOMAIN);
248
strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
249
strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
250
con->first_tree = con->last_tree = NULL;
252
SMB_Get_My_Name(con->myname, sizeof(con->myname));
254
con->port = 0; /* No port selected */
256
/* Get some things we need for the SMB Header */
259
con->mid = con->pid; /* This will do for now ... */
260
con->uid = 0; /* Until we have done a logon, no uid */
263
/* Now figure out the host portion of the service */
265
strcpy(temp, service);
266
host = (char *) strtok(temp, "/\\"); /* Separate host name portion */
267
strcpy(con->desthost, host);
269
/* Now connect to the remote end, but first upper case the name of the
270
* service we are going to call, sine some servers want it in uppercase */
272
for (i = 0; i < strlen(host); i++)
273
called[i] = xtoupper(host[i]);
275
called[strlen(host)] = 0; /* Make it a string */
277
for (i = 0; i < strlen(con->myname); i++)
278
calling[i] = xtoupper(con->myname[i]);
280
calling[strlen(con->myname)] = 0; /* Make it a string */
282
if (strcmp(con->address, "") == 0)
283
address = con->desthost;
285
address = con->address;
287
con->Trans_Connect = RFCNB_Call(called,
289
address, /* Protocol specific */
292
/* Did we get one? */
294
if (con->Trans_Connect == NULL) {
296
if (Con_Handle == NULL) {
300
SMBlib_errno = -SMBlibE_CallFailed;
305
/* Now, negotiate the protocol */
306
if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
308
/* Hmmm what should we do here ... We have a connection, but could not
313
/* Now connect to the service ... */
314
if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
321
/* Logon to the server. That is, do a session setup if we can. We do not do */
325
SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
326
char *PassWord, char *UserDomain, int precrypted)
328
struct RFCNB_Pkt *pkt;
329
int param_len, pkt_len, pass_len;
332
/* First we need a packet etc ... but we need to know what protocol has */
333
/* been negotiated to figure out if we can do it and what SMB format to */
336
if (Con_Handle->protocol < SMB_P_LanMan1) {
338
SMBlib_errno = SMBlibE_ProtLow;
339
return (SMBlibE_BAD);
344
memcpy(pword, PassWord, 24);
346
strcpy(pword, PassWord);
347
if (Con_Handle->encrypt_passwords) {
349
SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
351
pass_len = strlen(pword);
354
/* Now build the correct structure */
356
if (Con_Handle->protocol < SMB_P_NT1) {
358
param_len = strlen(UserName) + 1 + pass_len + 1 +
359
strlen(UserDomain) + 1 +
360
strlen(Con_Handle->OSName) + 1;
362
pkt_len = SMB_ssetpLM_len + param_len;
364
pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
368
SMBlib_errno = SMBlibE_NoSpace;
369
fprintf(stderr, "SMB_Logon_server: Couldn't allocate packet\n");
370
return (SMBlibE_BAD); /* Should handle the error */
372
memset(SMB_Hdr(pkt), 0, SMB_ssetpLM_len);
373
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
374
*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
375
SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
376
SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
377
SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
378
SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
379
*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
380
*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
381
SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
383
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
384
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
385
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle->pid);
386
SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
387
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
388
SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
389
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
391
/* Now copy the param strings in with the right stuff */
393
p = (char *) (SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
395
/* Copy in password, then the rest. Password has a null at end */
397
memcpy(p, pword, pass_len);
399
p = p + pass_len + 1;
402
p = p + strlen(UserName);
407
strcpy(p, UserDomain);
408
p = p + strlen(UserDomain);
412
strcpy(p, Con_Handle->OSName);
413
p = p + strlen(Con_Handle->OSName);
418
/* We don't admit to UNICODE support ... */
420
param_len = strlen(UserName) + 1 + pass_len +
421
strlen(UserDomain) + 1 +
422
strlen(Con_Handle->OSName) + 1 +
423
strlen(Con_Handle->LMType) + 1;
425
pkt_len = SMB_ssetpNTLM_len + param_len;
427
pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
431
SMBlib_errno = SMBlibE_NoSpace;
432
fprintf(stderr, "SMB_Logon_server: Couldn't allocate packet\n");
433
return (-1); /* Should handle the error */
435
memset(SMB_Hdr(pkt), 0, SMB_ssetpNTLM_len);
436
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
437
*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
438
SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
439
SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
440
SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
441
SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
442
*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
443
*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
444
SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
446
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
447
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
448
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 1); /* Thanks Tridge! */
449
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
450
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
451
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
452
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
453
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
454
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
456
/* Now copy the param strings in with the right stuff */
458
p = (char *) (SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
460
/* Copy in password, then the rest. Password has no null at end */
462
memcpy(p, pword, pass_len);
467
p = p + strlen(UserName);
472
strcpy(p, UserDomain);
473
p = p + strlen(UserDomain);
477
strcpy(p, Con_Handle->OSName);
478
p = p + strlen(Con_Handle->OSName);
482
strcpy(p, Con_Handle->LMType);
483
p = p + strlen(Con_Handle->LMType);
488
/* Now send it and get a response */
490
if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
493
fprintf(stderr, "Error sending SessSetupX request\n");
497
SMBlib_errno = SMBlibE_SendFailed;
498
return (SMBlibE_BAD);
501
/* Now get the response ... */
503
if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
506
fprintf(stderr, "Error receiving response to SessSetupAndX\n");
510
SMBlib_errno = SMBlibE_RecvFailed;
511
return (SMBlibE_BAD);
514
/* Check out the response type ... */
516
if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
519
fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
520
CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
521
SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
524
SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
526
SMBlib_errno = SMBlibE_Remote;
527
return (SMBlibE_BAD);
530
/** @@@ mdz: check for guest login { **/
531
if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1) {
532
/* do we allow guest login? NO! */
533
return (SMBlibE_BAD);
540
fprintf(stderr, "SessSetupAndX response. Action = %i\n",
541
SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
544
/* Now pick up the UID for future reference ... */
546
Con_Handle->uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
554
/* Disconnect from the server, and disconnect all tree connects */
557
SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
560
/* We just disconnect the connection for now ... */
561
if (Con_Handle != NULL)
562
RFCNB_Hangup(Con_Handle->Trans_Connect);