type.data is malloc'd by everyone BUT radeapclient, which
[freeradius.git] / src / modules / rlm_smb / smblib.c
1 /* UNIX SMBlib NetBIOS implementation
2
3    Version 1.0
4    SMBlib Routines
5
6    Copyright (C) Richard Sharpe 1996
7
8 */
9
10 /*
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.
15
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.
20
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.
24 */
25
26 int SMBlib_errno;
27 int SMBlib_SMB_Error;
28 #define SMBLIB_ERRNO
29 #define uchar unsigned char
30 #include "smblib-priv.h"
31
32 #include "rfcnb.h"
33
34 SMB_State_Types SMBlib_State;
35
36 /* Initialize the SMBlib package     */
37
38 int SMB_Init()
39
40 {
41
42   SMBlib_State = SMB_State_Started;
43
44   signal(SIGPIPE, SIG_IGN);   /* Ignore these ... */
45
46 /* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
47 #ifdef SMBLIB_INSTRUMENT
48
49   SMBlib_Instrument_Init();
50
51 #endif
52
53   return 0;
54
55 }
56
57 int SMB_Term()
58
59 {
60
61 #ifdef SMBLIB_INSTRUMENT
62
63   SMBlib_Instrument_Term();       /* Clean up and print results */
64
65 #endif
66
67   return 0;
68
69 }
70
71 /* SMB_Create: Create a connection structure and return for later use */
72 /* We have other helper routines to set variables                     */
73
74 SMB_Handle_Type SMB_Create_Con_Handle()
75
76 {
77
78   SMBlib_errno = SMBlibE_NotImpl;
79   return(NULL);
80
81 }
82
83 int SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
84
85 {
86
87
88   if (RFCNB_Set_Sock_NoDelay(Con_Handle -> Trans_Connect, yn) < 0) {
89
90 #ifdef DEBUG
91 #endif
92
93     fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
94
95   }
96
97   return(0);
98
99 }
100
101 /* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
102 /* or anything else ...                                                  */
103
104 SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
105                                    char *server, char *NTdomain)
106
107 { SMB_Handle_Type con;
108   char temp[80], called[80], calling[80], *address;
109   int i;
110
111   /* Get a connection structure if one does not exist */
112
113   con = Con_Handle;
114
115   if (Con_Handle == NULL) {
116
117     if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
118
119
120       SMBlib_errno = SMBlibE_NoSpace;
121       return NULL;
122     }
123
124   }
125
126   /* Init some things ... */
127
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;
138
139   SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
140
141   con -> port = 0;                    /* No port selected */
142
143   /* Get some things we need for the SMB Header */
144
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();
149
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 */
152
153   for (i=0; i < strlen(server); i++)
154     called[i] = toupper(server[i]);
155
156   called[strlen(server)] = 0;    /* Make it a string */
157
158   for (i=0; i < strlen(con -> myname); i++)
159     calling[i] = toupper(con -> myname[i]);
160
161   calling[strlen(con -> myname)] = 0;    /* Make it a string */
162
163   if (strcmp(con -> address, "") == 0)
164     address = con -> desthost;
165   else
166     address = con -> address;
167
168   con -> Trans_Connect = RFCNB_Call(called,
169                                     calling,
170                                     address, /* Protocol specific */
171                                     con -> port);
172
173   /* Did we get one? */
174
175   if (con -> Trans_Connect == NULL) {
176
177     if (Con_Handle == NULL) {
178       Con_Handle = NULL;
179       free(con);
180     }
181     SMBlib_errno = -SMBlibE_CallFailed;
182     return NULL;
183
184   }
185
186   return(con);
187
188 }
189
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                                              */
193
194 static const char *SMB_Prots_Restrict[] = {"PC NETWORK PROGRAM 1.0",
195                                           NULL};
196
197
198 SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle,
199                             SMB_Tree_Handle *tree,
200                             char *service,
201                             char *username,
202                             char *password)
203
204 { SMB_Handle_Type con;
205   char *host, *address;
206   char temp[80], called[80], calling[80];
207   int i;
208
209   /* Get a connection structure if one does not exist */
210
211   con = Con_Handle;
212
213   if (Con_Handle == NULL) {
214
215     if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
216
217       SMBlib_errno = SMBlibE_NoSpace;
218       return NULL;
219     }
220
221   }
222
223   /* Init some things ... */
224
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;
234
235   SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
236
237   con -> port = 0;                    /* No port selected */
238
239   /* Get some things we need for the SMB Header */
240
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();
245
246   /* Now figure out the host portion of the service */
247
248   strcpy(temp, service);
249   host = strtok(temp, "/\\");     /* Separate host name portion */
250   strcpy(con -> desthost, host);
251
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 */
254
255   for (i=0; i < strlen(host); i++)
256     called[i] = toupper(host[i]);
257
258   called[strlen(host)] = 0;    /* Make it a string */
259
260   for (i=0; i < strlen(con -> myname); i++)
261     calling[i] = toupper(con -> myname[i]);
262
263   calling[strlen(con -> myname)] = 0;    /* Make it a string */
264
265   if (strcmp(con -> address, "") == 0)
266     address = con -> desthost;
267   else
268     address = con -> address;
269
270   con -> Trans_Connect = RFCNB_Call(called,
271                                     calling,
272                                     address, /* Protocol specific */
273                                     con -> port);
274
275   /* Did we get one? */
276
277   if (con -> Trans_Connect == NULL) {
278
279     if (Con_Handle == NULL) {
280       free(con);
281       Con_Handle = NULL;
282     }
283     SMBlib_errno = -SMBlibE_CallFailed;
284     return NULL;
285
286   }
287
288   /* Now, negotiate the protocol */
289
290   if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
291
292     /* Hmmm what should we do here ... We have a connection, but could not
293        negotiate ...                                                      */
294
295     return NULL;
296
297   }
298
299   /* Now connect to the service ... */
300
301   if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
302
303     return NULL;
304
305   }
306
307   return(con);
308
309 }
310
311 /* Logon to the server. That is, do a session setup if we can. We do not do */
312 /* Unicode yet!                                                             */
313
314 int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
315                      char *PassWord)
316
317 { struct RFCNB_Pkt *pkt;
318   int param_len, i, pkt_len, pass_len,a;
319   char *p, pword[256];
320
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  */
323   /* use ...                                                               */
324
325   if (Con_Handle -> protocol < SMB_P_LanMan1) {
326
327     SMBlib_errno = SMBlibE_ProtLow;
328     return(SMBlibE_BAD);
329
330   }
331
332   strcpy(pword, PassWord);
333   if (Con_Handle -> encrypt_passwords)
334   {
335     pass_len=24;
336     SMBencrypt((uchar *) PassWord, (uchar *)Con_Handle -> Encrypt_Key,(uchar *)pword);
337   }
338   else
339         pass_len=strlen(pword);
340
341
342   /* Now build the correct structure */
343
344   if (Con_Handle -> protocol < SMB_P_NT1) {
345
346     param_len = strlen(UserName) + 1 + pass_len + 1 +
347                 strlen(Con_Handle -> PDomain) + 1 +
348                 strlen(Con_Handle -> OSName) + 1;
349
350     pkt_len = SMB_ssetpLM_len + param_len;
351
352     pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
353
354     if (pkt == NULL) {
355
356       SMBlib_errno = SMBlibE_NoSpace;
357       return(SMBlibE_BAD); /* Should handle the error */
358
359     }
360
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);
371
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);
379
380     /* Now copy the param strings in with the right stuff */
381
382     p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
383
384     /* Copy  in password, then the rest. Password has a null at end */
385
386     memcpy(p, pword, pass_len);
387
388     p = p + pass_len + 1;
389
390     strcpy(p, UserName);
391     p = p + strlen(UserName);
392     *p = 0;
393
394     p = p + 1;
395
396     strcpy(p, Con_Handle -> PDomain);
397     p = p + strlen(Con_Handle -> PDomain);
398     *p = 0;
399     p = p + 1;
400
401     strcpy(p, Con_Handle -> OSName);
402     p = p + strlen(Con_Handle -> OSName);
403     *p = 0;
404
405   }
406   else {
407
408     /* We don't admit to UNICODE support ... */
409
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;
414
415     pkt_len = SMB_ssetpNTLM_len + param_len;
416
417     pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
418
419     if (pkt == NULL) {
420
421       SMBlib_errno = SMBlibE_NoSpace;
422       return(-1); /* Should handle the error */
423
424     }
425
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);
436
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);
446
447     /* Now copy the param strings in with the right stuff */
448
449     p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
450
451     /* Copy  in password, then the rest. Password has no null at end */
452
453     memcpy(p, pword, pass_len);
454
455     p = p + pass_len;
456
457     strcpy(p, UserName);
458     p = p + strlen(UserName);
459     *p = 0;
460
461     p = p + 1;
462
463     strcpy(p, Con_Handle -> PDomain);
464     p = p + strlen(Con_Handle -> PDomain);
465   *p = 0;
466     p = p + 1;
467
468     strcpy(p, Con_Handle -> OSName);
469     p = p + strlen(Con_Handle -> OSName);
470     *p = 0;
471     p = p + 1;
472
473     strcpy(p, Con_Handle -> LMType);
474     p = p + strlen(Con_Handle -> LMType);
475     *p = 0;
476
477   }
478
479   /* Now send it and get a response */
480
481   if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
482
483 #ifdef DEBUG
484     fprintf(stderr, "Error sending SessSetupX request\n");
485 #endif
486
487     RFCNB_Free_Pkt(pkt);
488     SMBlib_errno = SMBlibE_SendFailed;
489     return(SMBlibE_BAD);
490
491   }
492
493   /* Now get the response ... */
494
495   if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
496
497 #ifdef DEBUG
498     fprintf(stderr, "Error receiving response to SessSetupAndX\n");
499 #endif
500
501     RFCNB_Free_Pkt(pkt);
502     SMBlib_errno = SMBlibE_RecvFailed;
503     return(SMBlibE_BAD);
504
505   }
506
507   /* Check out the response type ... */
508
509   if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {  /* Process error */
510
511 #ifdef DEBUG
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));
515 #endif
516
517     SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
518     RFCNB_Free_Pkt(pkt);
519     SMBlib_errno = SMBlibE_Remote;
520     return(SMBlibE_BAD);
521
522   }
523 /** @@@ mdz: check for guest login { **/
524        if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1)
525        {
526                /* do we allow guest login? NO! */
527                return(SMBlibE_BAD);
528
529        }
530  /** @@@ mdz: } **/
531
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
547
548 /* Disconnect from the server, and disconnect all tree connects */
549
550 int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
551
552 {
553
554   /* We just disconnect the connection for now ... */
555
556   RFCNB_Hangup(Con_Handle -> Trans_Connect);
557
558   if (!KeepHandle)
559     free(Con_Handle);
560
561   return(0);
562
563 }