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"
34 SMB_State_Types SMBlib_State;
36 /* Initialize the SMBlib package */
42 SMBlib_State = SMB_State_Started;
44 signal(SIGPIPE, SIG_IGN); /* Ignore these ... */
46 /* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
47 #ifdef SMBLIB_INSTRUMENT
49 SMBlib_Instrument_Init();
61 #ifdef SMBLIB_INSTRUMENT
63 SMBlib_Instrument_Term(); /* Clean up and print results */
71 /* SMB_Create: Create a connection structure and return for later use */
72 /* We have other helper routines to set variables */
74 SMB_Handle_Type SMB_Create_Con_Handle()
78 SMBlib_errno = SMBlibE_NotImpl;
83 int SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
88 if (RFCNB_Set_Sock_NoDelay(Con_Handle -> Trans_Connect, yn) < 0) {
93 fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
101 /* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
102 /* or anything else ... */
104 SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
105 char *server, char *NTdomain)
107 { SMB_Handle_Type con;
108 char temp[80], called[80], calling[80], *address;
111 /* Get a connection structure if one does not exist */
115 if (Con_Handle == NULL) {
117 if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
120 SMBlib_errno = SMBlibE_NoSpace;
126 /* Init some things ... */
128 strcpy(con -> service, "");
129 strcpy(con -> username, "");
130 strcpy(con -> password, "");
131 strcpy(con -> sock_options, "");
132 strcpy(con -> address, "");
133 strcpy(con -> desthost, server);
134 strcpy(con -> PDomain, NTdomain);
135 strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME);
136 strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE);
137 con -> first_tree = con -> last_tree = NULL;
139 SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
141 con -> port = 0; /* No port selected */
143 /* Get some things we need for the SMB Header */
145 con -> pid = getpid();
146 con -> mid = con -> pid; /* This will do for now ... */
147 con -> uid = 0; /* Until we have done a logon, no uid ... */
148 con -> gid = getgid();
150 /* Now connect to the remote end, but first upper case the name of the
151 service we are going to call, sine some servers want it in uppercase */
153 for (i=0; i < strlen(server); i++)
154 called[i] = toupper(server[i]);
156 called[strlen(server)] = 0; /* Make it a string */
158 for (i=0; i < strlen(con -> myname); i++)
159 calling[i] = toupper(con -> myname[i]);
161 calling[strlen(con -> myname)] = 0; /* Make it a string */
163 if (strcmp(con -> address, "") == 0)
164 address = con -> desthost;
166 address = con -> address;
168 con -> Trans_Connect = RFCNB_Call(called,
170 address, /* Protocol specific */
173 /* Did we get one? */
175 if (con -> Trans_Connect == NULL) {
177 if (Con_Handle == NULL) {
181 SMBlib_errno = -SMBlibE_CallFailed;
190 /* SMB_Connect: Connect to the indicated server */
191 /* If Con_Handle == NULL then create a handle and connect, otherwise */
192 /* use the handle passed */
194 static const char *SMB_Prots_Restrict[] = {"PC NETWORK PROGRAM 1.0",
198 SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle,
199 SMB_Tree_Handle *tree,
204 { SMB_Handle_Type con;
205 char *host, *address;
206 char temp[80], called[80], calling[80];
209 /* Get a connection structure if one does not exist */
213 if (Con_Handle == NULL) {
215 if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
217 SMBlib_errno = SMBlibE_NoSpace;
223 /* Init some things ... */
225 strcpy(con -> service, service);
226 strcpy(con -> username, username);
227 strcpy(con -> password, password);
228 strcpy(con -> sock_options, "");
229 strcpy(con -> address, "");
230 strcpy(con -> PDomain, SMBLIB_DEFAULT_DOMAIN);
231 strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME);
232 strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE);
233 con -> first_tree = con -> last_tree = NULL;
235 SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
237 con -> port = 0; /* No port selected */
239 /* Get some things we need for the SMB Header */
241 con -> pid = getpid();
242 con -> mid = con -> pid; /* This will do for now ... */
243 con -> uid = 0; /* Until we have done a logon, no uid */
244 con -> gid = getgid();
246 /* Now figure out the host portion of the service */
248 strcpy(temp, service);
249 host = strtok(temp, "/\\"); /* Separate host name portion */
250 strcpy(con -> desthost, host);
252 /* Now connect to the remote end, but first upper case the name of the
253 service we are going to call, sine some servers want it in uppercase */
255 for (i=0; i < strlen(host); i++)
256 called[i] = toupper(host[i]);
258 called[strlen(host)] = 0; /* Make it a string */
260 for (i=0; i < strlen(con -> myname); i++)
261 calling[i] = toupper(con -> myname[i]);
263 calling[strlen(con -> myname)] = 0; /* Make it a string */
265 if (strcmp(con -> address, "") == 0)
266 address = con -> desthost;
268 address = con -> address;
270 con -> Trans_Connect = RFCNB_Call(called,
272 address, /* Protocol specific */
275 /* Did we get one? */
277 if (con -> Trans_Connect == NULL) {
279 if (Con_Handle == NULL) {
283 SMBlib_errno = -SMBlibE_CallFailed;
288 /* Now, negotiate the protocol */
290 if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
292 /* Hmmm what should we do here ... We have a connection, but could not
299 /* Now connect to the service ... */
301 if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
311 /* Logon to the server. That is, do a session setup if we can. We do not do */
314 int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
317 { struct RFCNB_Pkt *pkt;
318 int param_len, i, pkt_len, pass_len,a;
321 /* First we need a packet etc ... but we need to know what protocol has */
322 /* been negotiated to figure out if we can do it and what SMB format to */
325 if (Con_Handle -> protocol < SMB_P_LanMan1) {
327 SMBlib_errno = SMBlibE_ProtLow;
332 strcpy(pword, PassWord);
333 if (Con_Handle -> encrypt_passwords)
336 SMBencrypt((uchar *) PassWord, (uchar *)Con_Handle -> Encrypt_Key,(uchar *)pword);
339 pass_len=strlen(pword);
342 /* Now build the correct structure */
344 if (Con_Handle -> protocol < SMB_P_NT1) {
346 param_len = strlen(UserName) + 1 + pass_len + 1 +
347 strlen(Con_Handle -> PDomain) + 1 +
348 strlen(Con_Handle -> OSName) + 1;
350 pkt_len = SMB_ssetpLM_len + param_len;
352 pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
356 SMBlib_errno = SMBlibE_NoSpace;
357 return(SMBlibE_BAD); /* Should handle the error */
361 bzero(SMB_Hdr(pkt), SMB_ssetpLM_len);
362 SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
363 *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
364 SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
365 SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
366 SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
367 SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
368 *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
369 *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
370 SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
372 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
373 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
374 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle -> pid);
375 SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
376 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
377 SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
378 SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
380 /* Now copy the param strings in with the right stuff */
382 p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
384 /* Copy in password, then the rest. Password has a null at end */
386 memcpy(p, pword, pass_len);
388 p = p + pass_len + 1;
391 p = p + strlen(UserName);
396 strcpy(p, Con_Handle -> PDomain);
397 p = p + strlen(Con_Handle -> PDomain);
401 strcpy(p, Con_Handle -> OSName);
402 p = p + strlen(Con_Handle -> OSName);
408 /* We don't admit to UNICODE support ... */
410 param_len = strlen(UserName) + 1 + pass_len +
411 strlen(Con_Handle -> PDomain) + 1 +
412 strlen(Con_Handle -> OSName) + 1 +
413 strlen(Con_Handle -> LMType) + 1;
415 pkt_len = SMB_ssetpNTLM_len + param_len;
417 pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
421 SMBlib_errno = SMBlibE_NoSpace;
422 return(-1); /* Should handle the error */
426 bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len);
427 SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
428 *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
429 SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
430 SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
431 SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
432 SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
433 *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
434 *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
435 SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
437 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
438 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
439 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0);
440 SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
441 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
442 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
443 SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
444 SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
445 SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
447 /* Now copy the param strings in with the right stuff */
449 p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
451 /* Copy in password, then the rest. Password has no null at end */
453 memcpy(p, pword, pass_len);
458 p = p + strlen(UserName);
463 strcpy(p, Con_Handle -> PDomain);
464 p = p + strlen(Con_Handle -> PDomain);
468 strcpy(p, Con_Handle -> OSName);
469 p = p + strlen(Con_Handle -> OSName);
473 strcpy(p, Con_Handle -> LMType);
474 p = p + strlen(Con_Handle -> LMType);
479 /* Now send it and get a response */
481 if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
484 fprintf(stderr, "Error sending SessSetupX request\n");
488 SMBlib_errno = SMBlibE_SendFailed;
493 /* Now get the response ... */
495 if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
498 fprintf(stderr, "Error receiving response to SessSetupAndX\n");
502 SMBlib_errno = SMBlibE_RecvFailed;
507 /* Check out the response type ... */
509 if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
512 fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
513 CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
514 SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
517 SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
519 SMBlib_errno = SMBlibE_Remote;
523 /** @@@ mdz: check for guest login { **/
524 if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1)
526 /* do we allow guest login? NO! */
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);
548 /* Disconnect from the server, and disconnect all tree connects */
550 int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
554 /* We just disconnect the connection for now ... */
556 RFCNB_Hangup(Con_Handle -> Trans_Connect);