add new header ident.h
[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 #include <ctype.h>
27 #include <string.h>
28 #include "smblib-priv.h"
29 #include "rfcnb.h"
30
31 #define SMBLIB_ERRNO
32 #define uchar unsigned char
33
34 int SMBlib_errno;
35 int SMBlib_SMB_Error;
36 SMB_State_Types SMBlib_State;
37
38 /* Initialize the SMBlib package     */
39
40 int SMB_Init()
41
42 {
43
44   SMBlib_State = SMB_State_Started;
45
46   signal(SIGPIPE, SIG_IGN);   /* Ignore these ... */
47
48 /* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
49 #ifdef SMBLIB_INSTRUMENT
50
51   SMBlib_Instrument_Init();
52
53 #endif
54
55   return 0;
56
57 }
58
59 int SMB_Term()
60
61 {
62
63 #ifdef SMBLIB_INSTRUMENT
64
65   SMBlib_Instrument_Term();       /* Clean up and print results */
66
67 #endif
68
69   return 0;
70
71 }
72
73 /* SMB_Create: Create a connection structure and return for later use */
74 /* We have other helper routines to set variables                     */
75
76 SMB_Handle_Type SMB_Create_Con_Handle()
77
78 {
79
80   SMBlib_errno = SMBlibE_NotImpl;
81   return(NULL);
82
83 }
84
85 int SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
86
87 {
88
89
90   if (RFCNB_Set_Sock_NoDelay(Con_Handle -> Trans_Connect, yn) < 0) {
91
92 #ifdef DEBUG
93 #endif
94
95     fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
96
97   }
98
99   return(0);
100
101 }
102
103 /* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
104 /* or anything else ...                                                  */
105
106 SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
107                                    char *server, char *NTdomain)
108
109 {
110   SMB_Handle_Type con;
111   char called[80], calling[80], *address;
112   int i;
113
114   /* Get a connection structure if one does not exist */
115
116   con = Con_Handle;
117
118   if (Con_Handle == NULL) {
119
120     if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
121
122
123       SMBlib_errno = SMBlibE_NoSpace;
124       return NULL;
125     }
126
127   }
128
129   /* Init some things ... */
130
131   strcpy(con -> service, "");
132   strcpy(con -> username, "");
133   strcpy(con -> password, "");
134   strcpy(con -> sock_options, "");
135   strcpy(con -> address, "");
136   strcpy(con -> desthost, server);
137   strcpy(con -> PDomain, NTdomain);
138   strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME);
139   strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE);
140   con -> first_tree = con -> last_tree = NULL;
141
142   SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
143
144   con -> port = 0;                    /* No port selected */
145
146   /* Get some things we need for the SMB Header */
147
148   con -> pid = getpid();
149   con -> mid = con -> pid;      /* This will do for now ... */
150   con -> uid = 0;               /* Until we have done a logon, no uid ... */
151   con -> gid = getgid();
152
153   /* Now connect to the remote end, but first upper case the name of the
154      service we are going to call, sine some servers want it in uppercase */
155
156   for (i=0; i < strlen(server); i++)
157     called[i] = toupper(server[i]);
158
159   called[strlen(server)] = 0;    /* Make it a string */
160
161   for (i=0; i < strlen(con -> myname); i++)
162     calling[i] = toupper(con -> myname[i]);
163
164   calling[strlen(con -> myname)] = 0;    /* Make it a string */
165
166   if (strcmp(con -> address, "") == 0)
167     address = con -> desthost;
168   else
169     address = con -> address;
170
171   con -> Trans_Connect = RFCNB_Call(called,
172                                     calling,
173                                     address, /* Protocol specific */
174                                     con -> port);
175
176   /* Did we get one? */
177
178   if (con -> Trans_Connect == NULL) {
179
180     if (Con_Handle == NULL) {
181       Con_Handle = NULL;
182       free(con);
183     }
184     SMBlib_errno = -SMBlibE_CallFailed;
185     return NULL;
186
187   }
188
189   return(con);
190
191 }
192
193 /* SMB_Connect: Connect to the indicated server                       */
194 /* If Con_Handle == NULL then create a handle and connect, otherwise  */
195 /* use the handle passed                                              */
196
197 static const char *SMB_Prots_Restrict[] = {"PC NETWORK PROGRAM 1.0",
198                                           NULL};
199
200
201 SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle,
202                             SMB_Tree_Handle *tree,
203                             char *service,
204                             char *username,
205                             char *password)
206
207 { SMB_Handle_Type con;
208   char *host, *address;
209   char temp[80], called[80], calling[80];
210   int i;
211
212   /* Get a connection structure if one does not exist */
213
214   con = Con_Handle;
215
216   if (Con_Handle == NULL) {
217
218     if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
219
220       SMBlib_errno = SMBlibE_NoSpace;
221       return NULL;
222     }
223
224   }
225
226   /* Init some things ... */
227
228   strcpy(con -> service, service);
229   strcpy(con -> username, username);
230   strcpy(con -> password, password);
231   strcpy(con -> sock_options, "");
232   strcpy(con -> address, "");
233   strcpy(con -> PDomain, SMBLIB_DEFAULT_DOMAIN);
234   strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME);
235   strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE);
236   con -> first_tree = con -> last_tree = NULL;
237
238   SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
239
240   con -> port = 0;                    /* No port selected */
241
242   /* Get some things we need for the SMB Header */
243
244   con -> pid = getpid();
245   con -> mid = con -> pid;      /* This will do for now ... */
246   con -> uid = 0;               /* Until we have done a logon, no uid */
247   con -> gid = getgid();
248
249   /* Now figure out the host portion of the service */
250
251   strcpy(temp, service);
252   host = strtok(temp, "/\\");     /* Separate host name portion */
253   strcpy(con -> desthost, host);
254
255   /* Now connect to the remote end, but first upper case the name of the
256      service we are going to call, sine some servers want it in uppercase */
257
258   for (i=0; i < strlen(host); i++)
259     called[i] = toupper(host[i]);
260
261   called[strlen(host)] = 0;    /* Make it a string */
262
263   for (i=0; i < strlen(con -> myname); i++)
264     calling[i] = toupper(con -> myname[i]);
265
266   calling[strlen(con -> myname)] = 0;    /* Make it a string */
267
268   if (strcmp(con -> address, "") == 0)
269     address = con -> desthost;
270   else
271     address = con -> address;
272
273   con -> Trans_Connect = RFCNB_Call(called,
274                                     calling,
275                                     address, /* Protocol specific */
276                                     con -> port);
277
278   /* Did we get one? */
279
280   if (con -> Trans_Connect == NULL) {
281
282     if (Con_Handle == NULL) {
283       free(con);
284       Con_Handle = NULL;
285     }
286     SMBlib_errno = -SMBlibE_CallFailed;
287     return NULL;
288
289   }
290
291   /* Now, negotiate the protocol */
292
293   if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
294
295     /* Hmmm what should we do here ... We have a connection, but could not
296        negotiate ...                                                      */
297
298     return NULL;
299
300   }
301
302   /* Now connect to the service ... */
303
304   if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
305
306     return NULL;
307
308   }
309
310   return(con);
311
312 }
313
314 /* Logon to the server. That is, do a session setup if we can. We do not do */
315 /* Unicode yet!                                                             */
316
317 int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
318                      char *PassWord)
319
320 {
321   struct RFCNB_Pkt *pkt;
322   int param_len, pkt_len, pass_len;
323   char *p, pword[256];
324
325   /* First we need a packet etc ... but we need to know what protocol has  */
326   /* been negotiated to figure out if we can do it and what SMB format to  */
327   /* use ...                                                               */
328
329   if (Con_Handle -> protocol < SMB_P_LanMan1) {
330
331     SMBlib_errno = SMBlibE_ProtLow;
332     return(SMBlibE_BAD);
333
334   }
335
336   strcpy(pword, PassWord);
337   if (Con_Handle -> encrypt_passwords)
338   {
339     pass_len=24;
340     SMBencrypt((uchar *) PassWord, (uchar *)Con_Handle -> Encrypt_Key,(uchar *)pword);
341   }
342   else
343         pass_len=strlen(pword);
344
345
346   /* Now build the correct structure */
347
348   if (Con_Handle -> protocol < SMB_P_NT1) {
349
350     param_len = strlen(UserName) + 1 + pass_len + 1 +
351                 strlen(Con_Handle -> PDomain) + 1 +
352                 strlen(Con_Handle -> OSName) + 1;
353
354     pkt_len = SMB_ssetpLM_len + param_len;
355
356     pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
357
358     if (pkt == NULL) {
359
360       SMBlib_errno = SMBlibE_NoSpace;
361       return(SMBlibE_BAD); /* Should handle the error */
362
363     }
364
365     bzero(SMB_Hdr(pkt), SMB_ssetpLM_len);
366     SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);  /* Plunk in IDF */
367     *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
368     SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
369     SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
370     SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
371     SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
372     *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
373     *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;    /* No extra command */
374     SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
375
376     SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
377     SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
378     SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle -> pid);
379     SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
380     SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
381     SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
382     SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
383
384     /* Now copy the param strings in with the right stuff */
385
386     p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
387
388     /* Copy  in password, then the rest. Password has a null at end */
389
390     memcpy(p, pword, pass_len);
391
392     p = p + pass_len + 1;
393
394     strcpy(p, UserName);
395     p = p + strlen(UserName);
396     *p = 0;
397
398     p = p + 1;
399
400     strcpy(p, Con_Handle -> PDomain);
401     p = p + strlen(Con_Handle -> PDomain);
402     *p = 0;
403     p = p + 1;
404
405     strcpy(p, Con_Handle -> OSName);
406     p = p + strlen(Con_Handle -> OSName);
407     *p = 0;
408
409   }
410   else {
411
412     /* We don't admit to UNICODE support ... */
413
414     param_len = strlen(UserName) + 1 + pass_len +
415                 strlen(Con_Handle -> PDomain) + 1 +
416                 strlen(Con_Handle -> OSName) + 1 +
417                 strlen(Con_Handle -> LMType) + 1;
418
419     pkt_len = SMB_ssetpNTLM_len + param_len;
420
421     pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
422
423     if (pkt == NULL) {
424
425       SMBlib_errno = SMBlibE_NoSpace;
426       return(-1); /* Should handle the error */
427
428     }
429
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);
440
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);
450
451     /* Now copy the param strings in with the right stuff */
452
453     p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
454
455     /* Copy  in password, then the rest. Password has no null at end */
456
457     memcpy(p, pword, pass_len);
458
459     p = p + pass_len;
460
461     strcpy(p, UserName);
462     p = p + strlen(UserName);
463     *p = 0;
464
465     p = p + 1;
466
467     strcpy(p, Con_Handle -> PDomain);
468     p = p + strlen(Con_Handle -> PDomain);
469   *p = 0;
470     p = p + 1;
471
472     strcpy(p, Con_Handle -> OSName);
473     p = p + strlen(Con_Handle -> OSName);
474     *p = 0;
475     p = p + 1;
476
477     strcpy(p, Con_Handle -> LMType);
478     p = p + strlen(Con_Handle -> LMType);
479     *p = 0;
480
481   }
482
483   /* Now send it and get a response */
484
485   if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
486
487 #ifdef DEBUG
488     fprintf(stderr, "Error sending SessSetupX request\n");
489 #endif
490
491     RFCNB_Free_Pkt(pkt);
492     SMBlib_errno = SMBlibE_SendFailed;
493     return(SMBlibE_BAD);
494
495   }
496
497   /* Now get the response ... */
498
499   if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
500
501 #ifdef DEBUG
502     fprintf(stderr, "Error receiving response to SessSetupAndX\n");
503 #endif
504
505     RFCNB_Free_Pkt(pkt);
506     SMBlib_errno = SMBlibE_RecvFailed;
507     return(SMBlibE_BAD);
508
509   }
510
511   /* Check out the response type ... */
512
513   if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {  /* Process error */
514
515 #ifdef DEBUG
516     fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
517             CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
518             SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
519 #endif
520
521     SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
522     RFCNB_Free_Pkt(pkt);
523     SMBlib_errno = SMBlibE_Remote;
524     return(SMBlibE_BAD);
525
526   }
527 /** @@@ mdz: check for guest login { **/
528        if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1)
529        {
530                /* do we allow guest login? NO! */
531                return(SMBlibE_BAD);
532
533        }
534  /** @@@ mdz: } **/
535
536
537 #ifdef DEBUG
538   fprintf(stderr, "SessSetupAndX response. Action = %i\n",
539           SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
540 #endif
541
542   /* Now pick up the UID for future reference ... */
543
544   Con_Handle -> uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
545   RFCNB_Free_Pkt(pkt);
546
547   return(0);
548
549 }
550
551
552 /* Disconnect from the server, and disconnect all tree connects */
553
554 int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
555
556 {
557
558   /* We just disconnect the connection for now ... */
559
560   RFCNB_Hangup(Con_Handle -> Trans_Connect);
561
562   if (!KeepHandle)
563     free(Con_Handle);
564
565   return(0);
566
567 }