]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/smblib/smblib.c
SourceFormat Enforcement
[thirdparty/squid.git] / lib / smblib / smblib.c
CommitLineData
f7f3304a 1#include "squid.h"
7c16470c
AJ
2
3/* UNIX SMBlib NetBIOS implementation
4
5 Version 1.0
6 SMBlib Routines
7
8 Copyright (C) Richard Sharpe 1996
9
10*/
11
12/*
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.
17
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.
22
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.
26*/
27
28int SMBlib_errno;
29int SMBlib_SMB_Error;
30#define SMBLIB_ERRNO
31
32#include "smblib/smblib.h"
33#include "smblib/smblib-priv.h"
34#include "rfcnb/rfcnb.h"
35
36#include <signal.h>
37#if HAVE_STRING_H
38#include <string.h>
39#endif
40
41SMB_State_Types SMBlib_State;
42
43const char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0",
3c96dd46
A
44 "MICROSOFT NETWORKS 1.03",
45 "MICROSOFT NETWORKS 3.0",
46 "DOS LANMAN1.0",
47 "LANMAN1.0",
48 "DOS LM1.2X002",
49 "LM1.2X002",
50 "DOS LANMAN2.1",
51 "LANMAN2.1",
52 "Samba",
53 "NT LM 0.12",
54 "NT LANMAN 1.0",
55 NULL
56 };
7c16470c 57
7c16470c
AJ
58/* Initialize the SMBlib package */
59
60int SMB_Init()
61
62{
63
64 SMBlib_State = SMB_State_Started;
65
66 signal(SIGPIPE, SIG_IGN); /* Ignore these ... */
67
68 /* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
69#ifdef SMBLIB_INSTRUMENT
70
71 SMBlib_Instrument_Init();
72
73#endif
74
75 return 0;
76
77}
78
7c16470c
AJ
79/* SMB_Create: Create a connection structure and return for later use */
80/* We have other helper routines to set variables */
81
82SMB_Handle_Type SMB_Create_Con_Handle()
83
84{
85
86 SMBlib_errno = SMBlibE_NotImpl;
87 return(NULL);
88
89}
90
7c16470c
AJ
91/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
92/* or anything else ... */
93
94SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
95 char *server, const char *NTdomain)
96
97{
98 SMB_Handle_Type con;
99 char called[80], calling[80], *address;
100 int i;
101
102 /* Get a connection structure if one does not exist */
103
104 con = Con_Handle;
105
106 if (Con_Handle == NULL) {
107
108 if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
109
7c16470c
AJ
110 SMBlib_errno = SMBlibE_NoSpace;
111 return NULL;
112 }
113
114 }
115
116 /* Init some things ... */
117
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;
128
129 SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
130
131 con -> port = 0; /* No port selected */
132
133 /* Get some things we need for the SMB Header */
134
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();
139
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 */
142
143 for (i=0; i < strlen(server); i++)
144 called[i] = toupper(server[i]);
145
146 called[strlen(server)] = 0; /* Make it a string */
147
148 for (i=0; i < strlen(con -> myname); i++)
149 calling[i] = toupper(con -> myname[i]);
150
151 calling[strlen(con -> myname)] = 0; /* Make it a string */
152
153 if (strcmp(con -> address, "") == 0)
154 address = con -> desthost;
155 else
156 address = con -> address;
157
158 con -> Trans_Connect = RFCNB_Call(called,
159 calling,
160 address, /* Protocol specific */
161 con -> port);
162
163 /* Did we get one? */
164
165 if (con -> Trans_Connect == NULL) {
166
167 if (Con_Handle == NULL) {
168 Con_Handle = NULL;
169 free(con);
170 }
171 SMBlib_errno = -SMBlibE_CallFailed;
172 return NULL;
173
174 }
175
176 return(con);
177
178}
179
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 */
183
184const char *SMB_Prots_Restrict[] = {"PC NETWORK PROGRAM 1.0",
185 NULL
186 };
187
7c16470c
AJ
188SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle,
189 SMB_Tree_Handle *tree,
190 char *service,
191 char *username,
192 char *password)
193
194{
195 SMB_Handle_Type con;
196 char *host, *address;
197 char temp[80], called[80], calling[80];
198 int i;
199
200 /* Get a connection structure if one does not exist */
201
202 con = Con_Handle;
203
204 if (Con_Handle == NULL) {
205
206 if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
207
208 SMBlib_errno = SMBlibE_NoSpace;
209 return NULL;
210 }
211
212 }
213
214 /* Init some things ... */
215
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;
225
226 SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
227
228 con -> port = 0; /* No port selected */
229
230 /* Get some things we need for the SMB Header */
231
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();
236
237 /* Now figure out the host portion of the service */
238
239 strcpy(temp, service);
240 host = strtok(temp, "/\\"); /* Separate host name portion */
241 strcpy(con -> desthost, host);
242
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 */
245
246 for (i=0; i < strlen(host); i++)
247 called[i] = toupper(host[i]);
248
249 called[strlen(host)] = 0; /* Make it a string */
250
251 for (i=0; i < strlen(con -> myname); i++)
252 calling[i] = toupper(con -> myname[i]);
253
254 calling[strlen(con -> myname)] = 0; /* Make it a string */
255
256 if (strcmp(con -> address, "") == 0)
257 address = con -> desthost;
258 else
259 address = con -> address;
260
261 con -> Trans_Connect = RFCNB_Call(called,
262 calling,
263 address, /* Protocol specific */
264 con -> port);
265
266 /* Did we get one? */
267
268 if (con -> Trans_Connect == NULL) {
269
270 if (Con_Handle == NULL) {
271 free(con);
272 Con_Handle = NULL;
273 }
274 SMBlib_errno = -SMBlibE_CallFailed;
275 return NULL;
276
277 }
278
279 /* Now, negotiate the protocol */
280
281 if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
282
283 /* Hmmm what should we do here ... We have a connection, but could not
284 negotiate ... */
285
286 return NULL;
287
288 }
289
290 /* Now connect to the service ... */
291
292 if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
293
294 return NULL;
295
296 }
297
298 return(con);
299
300}
301
302/* Logon to the server. That is, do a session setup if we can. We do not do */
303/* Unicode yet! */
304
305int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
306 char *PassWord, const char *NtDomain, int PreCrypted)
307
308{
309 struct RFCNB_Pkt *pkt;
310 int param_len, pkt_len, pass_len;
311 char *p, pword[128];
312
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 */
315 /* use ... */
316
317 if (Con_Handle -> protocol < SMB_P_LanMan1) {
318
319 SMBlib_errno = SMBlibE_ProtLow;
320 return(SMBlibE_BAD);
321
322 }
323
324 if (PreCrypted) {
325 pass_len = 24;
326 memcpy(pword, PassWord, 24);
327 } else {
328 strcpy(pword, PassWord);
329#ifdef PAM_SMB_ENC_PASS
330 if (Con_Handle->encrypt_passwords) {
331 pass_len = 24;
332 SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
333 } else
334#endif
335 pass_len = strlen(pword);
336 }
337
338 /* Now build the correct structure */
339
340 if (Con_Handle -> protocol < SMB_P_NT1) {
341
342 /* We don't handle encrypted passwords ... */
343
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;
347
348 pkt_len = SMB_ssetpLM_len + param_len;
349
350 pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
351
352 if (pkt == NULL) {
353
354 SMBlib_errno = SMBlibE_NoSpace;
355 return(SMBlibE_BAD); /* Should handle the error */
356
357 }
358
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);
369
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);
377
378 /* Now copy the param strings in with the right stuff */
379
380 p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
381
382 /* Copy in password, then the rest. Password has a null at end */
383
384 memcpy(p, pword, pass_len);
385
386 p = p + pass_len + 1;
387
388 strcpy(p, UserName);
389 p = p + strlen(UserName);
390 *p = 0;
391
392 p = p + 1;
393
394 if (NtDomain != NULL) {
395 strcpy(p, Con_Handle -> PDomain);
396 p = p + strlen(Con_Handle -> PDomain);
397 } else {
398 strcpy(p, NtDomain);
399 p = p + strlen(NtDomain);
400 }
401 *p = 0;
402 p = p + 1;
403
404 strcpy(p, Con_Handle -> OSName);
405 p = p + strlen(Con_Handle -> OSName);
406 *p = 0;
407
408 } else {
409
410 /* We don't admit to UNICODE support ... */
411
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;
416
417 pkt_len = SMB_ssetpNTLM_len + param_len;
418
419 pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
420
421 if (pkt == NULL) {
422
423 SMBlib_errno = SMBlibE_NoSpace;
424 return(-1); /* Should handle the error */
425
426 }
427
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);
438
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);
448
449 /* Now copy the param strings in with the right stuff */
450
451 p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
452
453 /* Copy in password, then the rest. Password has no null at end */
454
455 memcpy(p, pword, pass_len);
456
457 p = p + pass_len;
458
459 strcpy(p, UserName);
460 p = p + strlen(UserName);
461 *p = 0;
462
463 p = p + 1;
464
465 strcpy(p, Con_Handle -> PDomain);
466 p = p + strlen(Con_Handle -> PDomain);
467 *p = 0;
468 p = p + 1;
469
470 strcpy(p, Con_Handle -> OSName);
471 p = p + strlen(Con_Handle -> OSName);
472 *p = 0;
473 p = p + 1;
474
475 strcpy(p, Con_Handle -> LMType);
476 p = p + strlen(Con_Handle -> LMType);
477 *p = 0;
478
479 }
480
481 /* Now send it and get a response */
482
483 if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
484
485#ifdef DEBUG
486 fprintf(stderr, "Error sending SessSetupX request\n");
487#endif
488
489 RFCNB_Free_Pkt(pkt);
490 SMBlib_errno = SMBlibE_SendFailed;
491 return(SMBlibE_BAD);
492
493 }
494
495 /* Now get the response ... */
496
497 if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
498
499#ifdef DEBUG
500 fprintf(stderr, "Error receiving response to SessSetupAndX\n");
501#endif
502
503 RFCNB_Free_Pkt(pkt);
504 SMBlib_errno = SMBlibE_RecvFailed;
505 return(SMBlibE_BAD);
506
507 }
508
509 /* Check out the response type ... */
510
511 if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
512
513#ifdef DEBUG
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));
517#endif
518
519 SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
520 RFCNB_Free_Pkt(pkt);
521 SMBlib_errno = SMBlibE_Remote;
522 return(SMBlibE_BAD);
523
524 }
525
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);
530 }
531 /** @@@ mdz: } **/
532
533#ifdef DEBUG
534 fprintf(stderr, "SessSetupAndX response. Action = %i\n",
535 SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
536#endif
537
538 /* Now pick up the UID for future reference ... */
539
540 Con_Handle -> uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
541 RFCNB_Free_Pkt(pkt);
542
543 return(0);
544
545}
546
7c16470c
AJ
547/* Disconnect from the server, and disconnect all tree connects */
548
549int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
550
551{
552
553 /* We just disconnect the connection for now ... */
554
555 RFCNB_Hangup(Con_Handle -> Trans_Connect);
556
557 if (!KeepHandle)
558 free(Con_Handle);
559
560 return(0);
561
562}