1
/* UNIX SMBlib NetBIOS implementation
6
* Copyright (C) Richard Sharpe 1996
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* This program is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with this program; if not, write to the Free Software
23
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29
#define uchar unsigned char
30
#include "smblib-priv.h"
32
#include "rfcnb-priv.h"
34
#include "rfcnb-util.h"
43
SMB_State_Types SMBlib_State;
45
extern int RFCNB_Set_Sock_NoDelay(RFCNB_Con *, BOOL);
46
extern void SMB_Get_My_Name(char *, int);
48
/* Initialize the SMBlib package */
54
SMBlib_State = SMB_State_Started;
56
signal(SIGPIPE, SIG_IGN); /* Ignore these ... */
58
/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
59
#ifdef SMBLIB_INSTRUMENT
61
SMBlib_Instrument_Init();
73
#ifdef SMBLIB_INSTRUMENT
75
SMBlib_Instrument_Term(); /* Clean up and print results */
83
/* SMB_Create: Create a connection structure and return for later use */
84
/* We have other helper routines to set variables */
87
SMB_Create_Con_Handle(void)
90
SMBlib_errno = SMBlibE_NotImpl;
96
SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
100
if (RFCNB_Set_Sock_NoDelay(Con_Handle->Trans_Connect, yn) < 0) {
105
fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
112
/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
113
/* or anything else ... */
116
SMB_Connect_Server(SMB_Handle_Type Con_Handle,
117
char *server, char *NTdomain)
120
char called[80], calling[80], *address;
123
/* Get a connection structure if one does not exist */
127
if (Con_Handle == NULL) {
129
if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
132
SMBlib_errno = SMBlibE_NoSpace;
136
/* Init some things ... */
138
strcpy(con->service, "");
139
strcpy(con->username, "");
140
strcpy(con->password, "");
141
strcpy(con->sock_options, "");
142
strcpy(con->address, "");
143
strcpy(con->desthost, server);
144
strcpy(con->PDomain, NTdomain);
145
strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
146
strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
147
con->first_tree = con->last_tree = NULL;
149
SMB_Get_My_Name(con->myname, sizeof(con->myname));
151
con->port = 0; /* No port selected */
153
/* Get some things we need for the SMB Header */
156
con->mid = con->pid; /* This will do for now ... */
157
con->uid = 0; /* Until we have done a logon, no uid ... */
160
/* Now connect to the remote end, but first upper case the name of the
161
* service we are going to call, sine some servers want it in uppercase */
163
for (i = 0; i < strlen(server); i++)
164
called[i] = toupper(server[i]);
166
called[strlen(server)] = 0; /* Make it a string */
168
for (i = 0; i < strlen(con->myname); i++)
169
calling[i] = toupper(con->myname[i]);
171
calling[strlen(con->myname)] = 0; /* Make it a string */
173
if (strcmp(con->address, "") == 0)
174
address = con->desthost;
176
address = con->address;
178
con->Trans_Connect = RFCNB_Call(called,
180
address, /* Protocol specific */
183
/* Did we get one? */
185
if (con->Trans_Connect == NULL) {
187
if (Con_Handle == NULL) {
191
SMBlib_errno = -SMBlibE_CallFailed;
199
/* SMB_Connect: Connect to the indicated server */
200
/* If Con_Handle == NULL then create a handle and connect, otherwise */
201
/* use the handle passed */
203
char *SMB_Prots_Restrict[] =
204
{"PC NETWORK PROGRAM 1.0",
209
SMB_Connect(SMB_Handle_Type Con_Handle,
210
SMB_Tree_Handle * tree,
216
char *host, *address;
217
char temp[80], called[80], calling[80];
220
/* Get a connection structure if one does not exist */
224
if (Con_Handle == NULL) {
226
if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
228
SMBlib_errno = SMBlibE_NoSpace;
232
/* Init some things ... */
234
strcpy(con->service, service);
235
strcpy(con->username, username);
236
strcpy(con->password, password);
237
strcpy(con->sock_options, "");
238
strcpy(con->address, "");
239
strcpy(con->PDomain, SMBLIB_DEFAULT_DOMAIN);
240
strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
241
strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
242
con->first_tree = con->last_tree = NULL;
244
SMB_Get_My_Name(con->myname, sizeof(con->myname));
246
con->port = 0; /* No port selected */
248
/* Get some things we need for the SMB Header */
251
con->mid = con->pid; /* This will do for now ... */
252
con->uid = 0; /* Until we have done a logon, no uid */
255
/* Now figure out the host portion of the service */
257
strcpy(temp, service);
258
/* AI - Added (char *) to stop compiler warnings */
259
host = (char *) strtok(temp, "/\\"); /* Separate host name portion */
260
strcpy(con->desthost, host);
262
/* Now connect to the remote end, but first upper case the name of the
263
* service we are going to call, sine some servers want it in uppercase */
265
for (i = 0; i < strlen(host); i++)
266
called[i] = toupper(host[i]);
268
called[strlen(host)] = 0; /* Make it a string */
270
for (i = 0; i < strlen(con->myname); i++)
271
calling[i] = toupper(con->myname[i]);
273
calling[strlen(con->myname)] = 0; /* Make it a string */
275
if (strcmp(con->address, "") == 0)
276
address = con->desthost;
278
address = con->address;
280
con->Trans_Connect = RFCNB_Call(called,
282
address, /* Protocol specific */
285
/* Did we get one? */
287
if (con->Trans_Connect == NULL) {
289
if (Con_Handle == NULL) {
293
SMBlib_errno = -SMBlibE_CallFailed;
297
/* Now, negotiate the protocol */
299
if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
301
/* Hmmm what should we do here ... We have a connection, but could not
307
/* Now connect to the service ... */
309
if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
318
/* Logon to the server. That is, do a session setup if we can. We do not do */
322
SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
325
struct RFCNB_Pkt *pkt;
326
int param_len, pkt_len, pass_len;
329
/* First we need a packet etc ... but we need to know what protocol has */
330
/* been negotiated to figure out if we can do it and what SMB format to */
333
if (Con_Handle->protocol < SMB_P_LanMan1) {
335
SMBlib_errno = SMBlibE_ProtLow;
336
return (SMBlibE_BAD);
339
strcpy(pword, PassWord);
340
#ifdef PAM_SMB_ENC_PASS
341
if (Con_Handle->encrypt_passwords) {
343
SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
346
pass_len = strlen(pword);
349
/* Now build the correct structure */
351
if (Con_Handle->protocol < SMB_P_NT1) {
353
param_len = strlen(UserName) + 1 + pass_len + 1 +
354
strlen(Con_Handle->PDomain) + 1 +
355
strlen(Con_Handle->OSName) + 1;
357
pkt_len = SMB_ssetpLM_len + param_len;
359
pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
363
SMBlib_errno = SMBlibE_NoSpace;
364
return (SMBlibE_BAD); /* Should handle the error */
367
bzero(SMB_Hdr(pkt), SMB_ssetpLM_len);
368
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
369
*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
370
SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
371
SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
372
SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
373
SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
374
*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
375
*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
376
SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
378
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
379
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
380
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle->pid);
381
SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
382
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
383
SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
384
SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
386
/* Now copy the param strings in with the right stuff */
388
p = (char *) (SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
390
/* Copy in password, then the rest. Password has a null at end */
392
memcpy(p, pword, pass_len);
394
p = p + pass_len + 1;
397
p = p + strlen(UserName);
402
strcpy(p, Con_Handle->PDomain);
403
p = p + strlen(Con_Handle->PDomain);
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 */
430
bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len);
431
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
432
*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
433
SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
434
SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
435
SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
436
SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
437
*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
438
*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
439
SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
441
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
442
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
443
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0);
444
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
445
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
446
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
447
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
448
SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
449
SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
451
/* Now copy the param strings in with the right stuff */
453
p = (char *) (SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
455
/* Copy in password, then the rest. Password has no null at end */
457
memcpy(p, pword, pass_len);
462
p = p + strlen(UserName);
467
strcpy(p, Con_Handle->PDomain);
468
p = p + strlen(Con_Handle->PDomain);
472
strcpy(p, Con_Handle->OSName);
473
p = p + strlen(Con_Handle->OSName);
477
strcpy(p, Con_Handle->LMType);
478
p = p + strlen(Con_Handle->LMType);
483
/* Now send it and get a response */
485
if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
488
fprintf(stderr, "Error sending SessSetupX request\n");
492
SMBlib_errno = SMBlibE_SendFailed;
493
return (SMBlibE_BAD);
496
/* Now get the response ... */
498
if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
501
fprintf(stderr, "Error receiving response to SessSetupAndX\n");
505
SMBlib_errno = SMBlibE_RecvFailed;
506
return (SMBlibE_BAD);
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;
522
return (SMBlibE_BAD);
526
fprintf(stderr, "SessSetupAndX response. Action = %i\n",
527
SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
530
/* Now pick up the UID for future reference ... */
532
Con_Handle->uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
540
/* Disconnect from the server, and disconnect all tree connects */
543
SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
546
/* We just disconnect the connection for now ... */
548
RFCNB_Hangup(Con_Handle->Trans_Connect);