- Implemented RADIUS authentication
authorVictor Kirhenshtein <victor@netxms.org>
Mon, 12 Jun 2006 22:26:29 +0000 (22:26 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Mon, 12 Jun 2006 22:26:29 +0000 (22:26 +0000)
- GUID generation code replaced with moer clean from different source
- Started migration to GUIDs from 32bit user IDs

23 files changed:
.gitattributes
ChangeLog
doc/internal/db_format_change.txt
include/netxms-version.h
include/netxmsdb.h
include/uuid.h [new file with mode: 0644]
sql/schema.in
sql/setup.in
src/libnetxms/Makefile.nw
src/libnetxms/gen_uuid.c [new file with mode: 0644]
src/libnetxms/libnetxms.dsp
src/libnetxms/uuid.c
src/libnetxms/uuidP.h [new file with mode: 0644]
src/libnxcl/comm.cpp
src/server/core/Makefile.am
src/server/core/nxcore.dsp
src/server/core/radius.cpp [new file with mode: 0644]
src/server/core/radius.h [new file with mode: 0644]
src/server/core/session.cpp
src/server/core/users.cpp
src/server/include/nms_core.h
src/server/include/nms_users.h
src/server/libnxsrv/messages.mc

index c2be507..8e5bee8 100644 (file)
@@ -208,6 +208,7 @@ include/nxsnmp.h -text
 include/nxtools.h -text
 include/nxwinui.h -text
 include/unicode.h -text
+include/uuid.h -text
 m4/Makefile.am -text
 netware/Makefile.am -text
 netware/Makefile.inc -text
@@ -899,6 +900,7 @@ src/libnetxms/c_lgcc3.cpp -text
 src/libnetxms/config.cpp -text
 src/libnetxms/dir.c -text
 src/libnetxms/dload.cpp -text
+src/libnetxms/gen_uuid.c -text
 src/libnetxms/getopt.c -text
 src/libnetxms/hash.cpp -text
 src/libnetxms/icmp.cpp -text
@@ -924,6 +926,7 @@ src/libnetxms/threads.cpp -text
 src/libnetxms/tools.cpp -text
 src/libnetxms/unicode.cpp -text
 src/libnetxms/uuid.c -text
+src/libnetxms/uuidP.h -text
 src/libnxcl/Makefile.am -text
 src/libnxcl/actions.cpp -text
 src/libnxcl/alarms.cpp -text
@@ -1062,6 +1065,8 @@ src/server/core/objects.cpp -text
 src/server/core/objtools.cpp -text
 src/server/core/package.cpp -text
 src/server/core/poll.cpp -text
+src/server/core/radius.cpp -text
+src/server/core/radius.h -text
 src/server/core/rootobj.cpp -text
 src/server/core/script.cpp -text
 src/server/core/session.cpp -text
index 35f5380..f39489c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,7 @@
 * 0.2.12
 *
 
+- Implemented RADIUS authentication for NetXMS users
 - Added support for compressed MIB files
 - New MIBs added: ENTITY-MIB
 - Added support for DRBD device monitoring
index db4664b..ded7a46 100644 (file)
@@ -1,4 +1,18 @@
 *************
+* 40 ==> 41 *
+*************
+
+- New configuration parameters: RADIUSServer, RADIUSSecret, RADIUSPort,
+  RADIUSNumRetries, RADIUSTimeout
+- Added column "guid" to table "users":
+       ALTER TABLE users ADD guid varchar(32) not null;
+- Added column "auth_method" to table "users":
+       ALTER TABLE users ADD auth_method integer not null;
+- Added column "guid" to table "user_groups":
+       ALTER TABLE user_groups ADD guid varchar(32) not null;
+
+
+*************
 * 39 ==> 40 *
 *************
 
index da90ba9..b261aac 100644 (file)
@@ -38,7 +38,7 @@
 // Current client-server protocol version
 //
 
-#define CLIENT_PROTOCOL_VERSION     5
+#define CLIENT_PROTOCOL_VERSION     6
 
 
 #endif
index 6f5746f..b3ad278 100644 (file)
@@ -23,6 +23,6 @@
 #ifndef _netxms_db_h
 #define _netxms_db_h
 
-#define DB_FORMAT_VERSION      40
+#define DB_FORMAT_VERSION      41
 
 #endif
diff --git a/include/uuid.h b/include/uuid.h
new file mode 100644 (file)
index 0000000..8f613b7
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Public include file for the UUID library
+ * 
+ * Copyright (C) 1996, 1997, 1998 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU 
+ * Library General Public License.
+ * %End-Header%
+ */
+
+#ifndef _UUID_H_
+#define _UUID_H_
+
+#undef uuid_t
+typedef unsigned char uuid_t[16];
+
+/* UUID Variant definitions */
+#define UUID_VARIANT_NCS       0
+#define UUID_VARIANT_DCE       1
+#define UUID_VARIANT_MICROSOFT 2
+#define UUID_VARIANT_OTHER     3
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void LIBNETXMS_EXPORTABLE uuid_clear(uuid_t uu);
+int LIBNETXMS_EXPORTABLE uuid_compare(uuid_t uu1, uuid_t uu2);
+void LIBNETXMS_EXPORTABLE uuid_copy(uuid_t uu1, uuid_t uu2);
+void LIBNETXMS_EXPORTABLE uuid_generate(uuid_t out);
+int LIBNETXMS_EXPORTABLE uuid_is_null(uuid_t uu);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+int uuid_parse(char *in, uuid_t uu);
+void uuid_unparse(uuid_t uu, char *out);
+*/
+
+#endif
index 505feab..05886d4 100644 (file)
@@ -45,6 +45,7 @@ CREATE TABLE modules
 CREATE TABLE users
 (
        id integer not null,
+       guid varchar(32) not null,
        name varchar(63) not null,
        password varchar(48) not null,
        system_access integer not null,
@@ -52,6 +53,7 @@ CREATE TABLE users
        full_name varchar(127) not null,
        description varchar(255) not null,
        grace_logins integer not null,
+       auth_method integer not null,
        PRIMARY KEY(id)
 ) TABLE_TYPE;
 
@@ -63,10 +65,11 @@ CREATE TABLE users
 CREATE TABLE user_groups
 (
        id integer not null,
+       guid varchar(32) not null,
        name varchar(63) not null,
-       system_access integer,
-       flags integer,
-       description varchar(255),
+       system_access integer not null,
+       flags integer not null,
+       description varchar(255) not null,
        PRIMARY KEY(id)
 ) TABLE_TYPE;
 
@@ -91,7 +94,7 @@ CREATE TABLE user_profiles
 (
        user_id integer not null,
        var_name varchar(255) not null,
-       var_value SQL_TEXT,
+       var_value SQL_TEXT not null,
        PRIMARY KEY(user_id,var_name)
 ) TABLE_TYPE;
 
index 727609c..be8e7b4 100644 (file)
@@ -126,6 +126,16 @@ INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
        VALUES ('DisableVacuum','0',1,0);
 INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
        VALUES ('LockTimeout','60000',1,1);
+INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+       VALUES ('RADIUSServer','localhost',1,0);
+INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+       VALUES ('RADIUSSecret','netxms',1,0);
+INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+       VALUES ('RADIUSPort','1645',1,0);
+INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+       VALUES ('RADIUSNumRetries','5',1,0);
+INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+       VALUES ('RADIUSTimeout','3',1,0);
 
 
 /*
index 865b997..6f10115 100644 (file)
@@ -5,8 +5,9 @@
 
 include ../../netware/Makefile.inc
 
-OBJECTS  = c_lgcc3.o config.o dload.o hash.o icmp.o inline.o main.o md5.o \
-           queue.o sha1.o strtoll.o strtoull.o tools.o unicode.o uuid.o
+OBJECTS  = c_lgcc3.o config.o gen_uuid.o dload.o hash.o icmp.o inline.o \
+          main.o md5.o queue.o sha1.o strtoll.o strtoull.o tools.o \
+          unicode.o uuid.o
 EXEC     = netxms.nlm
 DEF      = netxms.def
 OBJTMP   = netxms_r.o
diff --git a/src/libnetxms/gen_uuid.c b/src/libnetxms/gen_uuid.c
new file mode 100644 (file)
index 0000000..fbe4c76
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * gen_uuid.c --- generate a DCE-compatible uuid
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU 
+ * Library General Public License.
+ * %End-Header%
+ */
+
+/*
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+*/
+
+#include "libnetxms.h"
+#include "uuidP.h"
+
+#ifdef HAVE_SRANDOM
+#define srand(x)       srandom(x)
+#define rand()                 random()
+#endif
+
+#ifndef _WIN32
+
+static int get_random_fd()
+{
+       int fd = -2;
+       int     i;
+
+       if (fd == -2)
+   {
+               fd = open("/dev/urandom", O_RDONLY);
+               if (fd == -1)
+                       fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+               srand((getpid() << 16) ^ getuid() ^ time(0));
+       }
+       /* Crank the random number generator a few times */
+       for (i = time(0) & 0x1F; i > 0; i--)
+               rand();
+       return fd;
+}
+
+#endif
+
+
+/*
+ * Generate a series of random bytes.  Use /dev/urandom if possible,
+ * and if not, use srandom/random.
+ */
+
+static void get_random_bytes(void *buf, int nbytes)
+{
+       int i;
+       char *cp = (char *)buf;
+#ifndef _WIN32
+   int fd = get_random_fd();
+       int lose_counter = 0;
+
+       if (fd >= 0)
+   {
+               while (nbytes > 0)
+      {
+                       i = read(fd, cp, nbytes);
+                       if ((i < 0) &&
+                           ((errno == EINTR) || (errno == EAGAIN)))
+                               continue;
+                       if (i <= 0) {
+                               if (lose_counter++ == 8)
+                                       break;
+                               continue;
+                       }
+                       nbytes -= i;
+                       cp += i;
+                       lose_counter = 0;
+               }
+               close(fd);
+       }
+#endif
+       if (nbytes == 0)
+               return;
+
+       /* XXX put something better here if no /dev/random! */
+       for (i=0; i < nbytes; i++)
+               *cp++ = rand() & 0xFF;
+       return;
+}
+
+/*
+ * Get the ethernet hardware address, if we can find it...
+ */
+static int get_node_id(unsigned char *node_id)
+{
+#ifdef HAVE_NET_IF_H
+       int             sd;
+       struct ifreq    ifr, *ifrp;
+       struct ifconf   ifc;
+       char buf[1024];
+       int             n, i;
+       unsigned char   *a;
+       
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is 
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+     sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN*/
+
+#ifdef AF_INET6
+       sd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP);
+       if (sd < 0)
+#endif
+       {
+               sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+               if (sd < 0) {
+                       return -1;
+               }
+       }
+       memset(buf, 0, sizeof(buf));
+       ifc.ifc_len = sizeof(buf);
+       ifc.ifc_buf = buf;
+       if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
+               close(sd);
+               return -1;
+       }
+       n = ifc.ifc_len;
+       for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
+               ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
+               strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
+#ifdef SIOCGIFHWADDR
+               if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
+                       continue;
+               a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
+#else
+#ifdef SIOCGENADDR
+               if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
+                       continue;
+               a = (unsigned char *) ifr.ifr_enaddr;
+#else
+               /*
+                * XXX we don't have a way of getting the hardware
+                * address
+                */
+               close(sd);
+               return 0;
+#endif /* SIOCGENADDR */
+#endif /* SIOCGIFHWADDR */
+               if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
+                       continue;
+               if (node_id) {
+                       memcpy(node_id, a, 6);
+                       close(sd);
+                       return 1;
+               }
+       }
+       close(sd);
+#endif
+       return 0;
+}
+
+/* Assume that the gettimeofday() has microsecond granularity */
+#define MAX_ADJUSTMENT 10
+
+static int get_clock(DWORD *clock_high, DWORD *clock_low, WORD *ret_clock_seq)
+{
+       static int adjustment = 0;
+       static struct timeval last = {0, 0};
+       static unsigned short clock_seq;
+       struct timeval tv;
+       QWORD clock_reg;
+#ifdef _WIN32
+   FILETIME ft;
+   LARGE_INTEGER li;
+   __int64 t;
+#endif
+       
+try_again:
+#ifdef _WIN32
+   GetSystemTimeAsFileTime(&ft);
+   li.LowPart  = ft.dwLowDateTime;
+   li.HighPart = ft.dwHighDateTime;
+   t = li.QuadPart;       // In 100-nanosecond intervals
+   t /= 10;    // To microseconds
+   tv.tv_sec = (time_t)(t / 1000000);
+   tv.tv_usec = (time_t)(t % 1000000);
+#else
+       gettimeofday(&tv, NULL);
+#endif
+       if ((last.tv_sec == 0) && (last.tv_usec == 0))
+   {
+               get_random_bytes(&clock_seq, sizeof(clock_seq));
+               clock_seq &= 0x1FFF;
+               last = tv;
+               last.tv_sec--;
+       }
+       if ((tv.tv_sec < last.tv_sec) ||
+           ((tv.tv_sec == last.tv_sec) &&
+            (tv.tv_usec < last.tv_usec)))
+   {
+               clock_seq = (clock_seq + 1) & 0x1FFF;
+               adjustment = 0;
+               last = tv;
+       }
+   else if ((tv.tv_sec == last.tv_sec) &&
+           (tv.tv_usec == last.tv_usec))
+   {
+               if (adjustment >= MAX_ADJUSTMENT)
+                       goto try_again;
+               adjustment++;
+       }
+   else
+   {
+               adjustment = 0;
+               last = tv;
+       }
+               
+       clock_reg = tv.tv_usec * 10 + adjustment;
+       clock_reg += ((QWORD)tv.tv_sec) * 10000000;
+       clock_reg += (((QWORD)0x01B21DD2) << 32) + 0x13814000;
+
+       *clock_high = (DWORD)(clock_reg >> 32);
+       *clock_low = (DWORD)clock_reg;
+       *ret_clock_seq = clock_seq;
+       return 0;
+}
+
+static void uuid_generate_time(uuid_t out)
+{
+       static unsigned char node_id[6];
+       static int has_init = 0;
+       struct uuid uu;
+       DWORD clock_mid;
+
+       if (!has_init)
+   {
+               if (get_node_id(node_id) <= 0)
+      {
+                       get_random_bytes(node_id, 6);
+                       /*
+                        * Set multicast bit, to prevent conflicts
+                        * with IEEE 802 addresses obtained from
+                        * network cards
+                        */
+                       node_id[0] |= 0x80;
+               }
+               has_init = 1;
+       }
+       get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
+       uu.clock_seq |= 0x8000;
+       uu.time_mid = (WORD)clock_mid;
+       uu.time_hi_and_version = (WORD)((clock_mid >> 16) | 0x1000);
+       memcpy(uu.node, node_id, 6);
+       uuid_pack(&uu, out);
+}
+
+static void uuid_generate_random(uuid_t out)
+{
+       uuid_t  buf;
+       struct uuid uu;
+
+       get_random_bytes(buf, sizeof(buf));
+       uuid_unpack(buf, &uu);
+
+       uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+       uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
+       uuid_pack(&uu, out);
+}
+
+/*
+ * This is the generic front-end to uuid_generate_random and
+ * uuid_generate_time.  It uses uuid_generate_random only if
+ * /dev/urandom is available, since otherwise we won't have
+ * high-quality randomness.
+ */
+void LIBNETXMS_EXPORTABLE uuid_generate(uuid_t out)
+{
+#ifndef _WIN32
+       int fd;
+
+       fd = get_random_fd();
+       if (fd >= 0)
+   {
+               close(fd);
+               uuid_generate_random(out);
+       }
+       else
+#endif
+               uuid_generate_time(out);
+}
index a5f9f23..bf58931 100644 (file)
@@ -55,7 +55,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /version:0.1 /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib ntdll.lib /nologo /version:0.1 /dll /machine:I386
 # Begin Special Build Tool
 SOURCE="$(InputPath)"
 PostBuild_Desc=Copy files
@@ -119,7 +119,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /version:0.1 /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib bufferoverflowU.lib /nologo /version:0.1 /dll /debug /machine:IX86 /pdbtype:sept /machine:AMD64
+# ADD LINK32 bufferoverflowU.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib ntdll.lib /nologo /version:0.1 /dll /debug /machine:IX86 /pdbtype:sept /machine:AMD64
 # SUBTRACT LINK32 /pdb:none
 # Begin Special Build Tool
 SOURCE="$(InputPath)"
@@ -152,7 +152,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /version:0.1 /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib bufferoverflowU.lib /nologo /version:0.1 /dll /machine:IX86 /machine:AMD64
+# ADD LINK32 bufferoverflowU.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib ntdll.lib /nologo /version:0.1 /dll /machine:IX86 /machine:AMD64
 # SUBTRACT LINK32 /pdb:none
 # Begin Special Build Tool
 SOURCE="$(InputPath)"
@@ -185,6 +185,10 @@ SOURCE=.\dload.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\gen_uuid.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\getopt.c
 # End Source File
 # Begin Source File
@@ -303,6 +307,10 @@ SOURCE=..\..\include\unicode.h
 
 SOURCE=..\..\include\uuid.h
 # End Source File
+# Begin Source File
+
+SOURCE=.\uuidP.h
+# End Source File
 # End Group
 # Begin Group "Resource Files"
 
index e48f0db..efeee86 100644 (file)
-/*
- ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
- ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
- ** Digital Equipment Corporation, Maynard, Mass.
- ** Copyright (c) 1998 Microsoft.
- ** To anyone who acknowledges that this file is provided "AS IS"
- ** without any express or implied warranty: permission to use, copy,
- ** modify, and distribute this file for any purpose is hereby
- ** granted without fee, provided that the above copyright notices and
- ** this notice appears in all source code copies, and that none of
- ** the names of Open Software Foundation, Inc., Hewlett-Packard
- ** Company, or Digital Equipment Corporation be used in advertising
- ** or publicity pertaining to distribution of the software without
- ** specific, written prior permission.  Neither Open Software
- ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
- ** Corporation makes any representations about the suitability of
- ** this software for any purpose.
- */
+/* 
+** libuuid integrated into NetXMS project
+** Copyright (C) 1996, 1997 Theodore Ts'o.
+** Integrated into NetXMS by Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: uuid.cpp
+**
+**/
 
 #include "libnetxms.h"
-#include <uuid.h>
+#include "uuidP.h"
 
-#ifndef _WIN32
-#ifdef HAVE_SYS_SYSINFO_H
-#  include <sys/sysinfo.h>
-#else
-#  include <unistd.h>
-#endif
-#endif
 
-/* MD5 */
-#include "md5.h"
-#define MD5_CTX md5_state_t
+//
+// Clear a UUID
+//
 
-/* set the following to the number of 100ns ticks of the actual
-resolution of
-your system's clock */
-#define UUIDS_PER_TICK 1024
-
-/* Set the following to a call to acquire a system wide global lock
-*/
-#define LOCK
-#define UNLOCK
-
-typedef QWORD uuid_time_t;
-typedef struct {
-  char nodeID[6];
-} uuid_node_t;
-
-/* various forward declarations */
-static int read_state(WORD *clockseq, uuid_time_t *timestamp,
-uuid_node_t * node);
-static void write_state(WORD clockseq, uuid_time_t timestamp,
-uuid_node_t node);
-static void format_uuid_v1(uuid_t * uuid, WORD clockseq,
-uuid_time_t timestamp, uuid_node_t node);
-static void format_uuid_v3(uuid_t * uuid, unsigned char hash[16]);
-static void get_current_time(uuid_time_t * timestamp);
-static WORD true_random(void);
-
-
-#ifdef _WIN32
-
-static void get_system_time(uuid_time_t *uuid_time)
-{
-  ULARGE_INTEGER time;
-
-  GetSystemTimeAsFileTime((FILETIME *)&time);
-
-    /* NT keeps time in FILETIME format which is 100ns ticks since
-     Jan 1, 1601.  UUIDs use time in 100ns ticks since Oct 15, 1582.
-     The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
-     + 18 years and 5 leap days.
-  */
-
-    time.QuadPart +=
-          (unsigned __int64) (1000*1000*10)       // seconds
-        * (unsigned __int64) (60 * 60 * 24)       // days
-        * (unsigned __int64) (17+30+31+365*18+5); // # of days
-
-  *uuid_time = time.QuadPart;
-
-};
-
-static void get_random_info(char seed[16])
-{
-  MD5_CTX c;
-  typedef struct {
-      MEMORYSTATUS m;
-      SYSTEM_INFO s;
-      FILETIME t;
-      LARGE_INTEGER pc;
-      DWORD tc;
-      DWORD l;
-      char hostname[MAX_COMPUTERNAME_LENGTH + 1];
-  } randomness;
-  randomness r;
-
-  I_md5_init(&c);
-  /* memory usage stats */
-  GlobalMemoryStatus(&r.m);
-  /* random system stats */
-  GetSystemInfo(&r.s);
-  /* 100ns resolution (nominally) time of day */
-  GetSystemTimeAsFileTime(&r.t);
-  /* high resolution performance counter */
-  QueryPerformanceCounter(&r.pc);
-  /* milliseconds since last boot */
-  r.tc = GetTickCount();
-  r.l = MAX_COMPUTERNAME_LENGTH + 1;
-
-  GetComputerName(r.hostname, &r.l );
-  I_md5_append(&c, (md5_byte_t *)&r, sizeof(randomness));
-  I_md5_finish(&c, seed);
-};
-
-#else
-
-static void get_system_time(uuid_time_t *uuid_time)
-{
-    struct timeval tp;
-
-    gettimeofday(&tp, (struct timezone *)0);
-
-    /* Offset between UUID formatted times and Unix formatted times.
-       UUID UTC base time is October 15, 1582.
-       Unix base time is January 1, 1970.
-    */
-    *uuid_time = (tp.tv_sec * 10000000) + (tp.tv_usec * 10) + 0x01B21DD213814000;
-}
-
-static void get_random_info(char seed[16])
+void LIBNETXMS_EXPORTABLE uuid_clear(uuid_t uu)
 {
-   MD5_CTX c;
-   typedef struct
-   {
-#ifdef HAVE_SYS_SYSINFO_H
-      struct sysinfo s;
-#else
-      long clock_tick;
-      long open_max;
-      long stream_max;
-      long expr_nest_max;
-      long bc_scale_max;
-      long bc_string_max;
-#endif
-      struct timeval t;
-      char hostname[257];
-   } randomness;
-   randomness r;
-
-   I_md5_init(&c);
-
-#ifdef HAVE_SYS_SYSINFO_H
-   sysinfo(&r.s);
-#else
-   r.clock_tick    = sysconf(_SC_CLK_TCK);
-   r.open_max      = sysconf(_SC_OPEN_MAX);
-   r.stream_max    = sysconf(_SC_STREAM_MAX);
-#ifdef _SC_EXPR_NEST_MAX
-   r.expr_nest_max = sysconf(_SC_EXPR_NEST_MAX);
-#endif
-#ifdef _SC_BC_SCALE_MAX
-   r.bc_scale_max  = sysconf(_SC_BC_SCALE_MAX);
-#endif
-#ifdef _SC_BC_STRING_MAX
-   r.bc_string_max = sysconf(_SC_BC_STRING_MAX);
-#endif
-#endif
-
-   gettimeofday(&r.t, (struct timezone *)0);
-   gethostname(r.hostname, 256);
-   I_md5_append(&c, (md5_byte_t *)&r, sizeof(randomness));
-   I_md5_finish(&c, (md5_byte_t *)seed);
+       memset(uu, 0, 16);
 }
 
-#endif
-
-
-static void get_node_identifier(uuid_node_t *node)
-{
-  char seed[16];
-  FILE * fd;
-  static int inited = 0;
-  static uuid_node_t saved_node;
-
-  if (!inited)
-  {
-      fd = fopen("nodeid", "rb");
-      if (fd)
-      {
-           fread(&saved_node, sizeof(uuid_node_t), 1, fd);
-           fclose(fd);
-      }
-      else
-      {
-           get_random_info(seed);
-           seed[0] |= 0x80;
-           memcpy(&saved_node, seed, sizeof(uuid_node_t));
-           fd = fopen("nodeid", "wb");
-           if (fd) {
-                  fwrite(&saved_node, sizeof(uuid_node_t), 1, fd);
-                  fclose(fd);
-           };
-      };
-      inited = 1;
-  };
+#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
 
-  *node = saved_node;
-};
 
+//
+// compare whether or not two UUID's are the same
+//
+// Returns 0 if the two UUID's are different, and 1 if they are the same.
+//
 
-/* uuid_create -- generator a UUID */
-int LIBNETXMS_EXPORTABLE uuid_create(uuid_t * uuid)
+int LIBNETXMS_EXPORTABLE uuid_compare(uuid_t uu1, uuid_t uu2)
 {
-  uuid_time_t timestamp, last_time;
-  WORD clockseq;
-  uuid_node_t node;
-  uuid_node_t last_node;
-  int f;
-
-  /* acquire system wide lock so we're alone */
-  LOCK;
-
-  /* get current time */
-  get_current_time(&timestamp);
-
-  /* get node ID */
-  get_node_identifier(&node);
-
-  /* get saved state from NV storage */
-  f = read_state(&clockseq, &last_time, &last_node);
-
-  /* if no NV state, or if clock went backwards, or node ID changed
-     (e.g., net card swap) change clockseq */
-  if (!f || memcmp(&node, &last_node, sizeof(uuid_node_t)))
-      clockseq = true_random();
-  else if (timestamp < last_time)
-      clockseq++;
+       struct uuid     uuid1, uuid2;
 
-  /* stuff fields into the UUID */
-  format_uuid_v1(uuid, clockseq, timestamp, node);
-
-  /* save the state for next time */
-  write_state(clockseq, timestamp, node);
-
-  UNLOCK;
-  return(1);
-};
-
-/* format_uuid_v1 -- make a UUID from the timestamp, clockseq,
-                     and node ID */
-static void format_uuid_v1(uuid_t * uuid, WORD clock_seq, uuid_time_t
-timestamp, uuid_node_t node) {
-    /* Construct a version 1 uuid with the information we've gathered
-     * plus a few constants. */
-  uuid->time_low = (DWORD)(timestamp & 0xFFFFFFFF);
-    uuid->time_mid = (WORD)((timestamp >> 32) & 0xFFFF);
-    uuid->time_hi_and_version = (WORD)((timestamp >> 48) &
-       0x0FFF);
-    uuid->time_hi_and_version |= (1 << 12);
-    uuid->clock_seq_low = clock_seq & 0xFF;
-    uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
-    uuid->clock_seq_hi_and_reserved |= 0x80;
-    memcpy(&uuid->node, &node, sizeof uuid->node);
-};
-
-/* data type for UUID generator persistent state */
-typedef struct {
-  uuid_time_t ts;       /* saved timestamp */
-  uuid_node_t node;     /* saved node ID */
-  WORD cs;        /* saved clock sequence */
-  } uuid_state;
-
-static uuid_state st;
-
-/* read_state -- read UUID generator state from non-volatile store */
-static int read_state(WORD *clockseq, uuid_time_t *timestamp,
-                      uuid_node_t *node) 
-{
-   FILE * fd;
-   static int inited = 0;
+       uuid_unpack(uu1, &uuid1);
+       uuid_unpack(uu2, &uuid2);
 
-   /* only need to read state once per boot */
-   if (!inited)
-   {
-      fd = fopen("state", "rb");
-      if (!fd)
-         return 0;
-      fread(&st, sizeof(uuid_state), 1, fd);
-      fclose(fd);
-      inited = 1;
-   }
-   *clockseq = st.cs;
-   *timestamp = st.ts;
-   *node = st.node;
-   return 1;
-};
+       UUCMP(uuid1.time_low, uuid2.time_low);
+       UUCMP(uuid1.time_mid, uuid2.time_mid);
+       UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
+       UUCMP(uuid1.clock_seq, uuid2.clock_seq);
+       return memcmp(uuid1.node, uuid2.node, 6);
+}
 
-/* write_state -- save UUID generator state back to non-volatile storage */
-static void write_state(WORD clockseq, uuid_time_t timestamp,
-                        uuid_node_t node)
-{
-  FILE * fd;
-  static int inited = 0;
-  static uuid_time_t next_save;
 
-  if (!inited)
-  {
-      next_save = timestamp;
-      inited = 1;
-  };
-  /* always save state to volatile shared state */
-  st.cs = clockseq;
-  st.ts = timestamp;
-  st.node = node;
-  if (timestamp >= next_save)
-  {
-      fd = fopen("state", "wb");
-      fwrite(&st, sizeof(uuid_state), 1, fd);
-      fclose(fd);
-      /* schedule next save for 10 seconds from now */
-      next_save = timestamp + (10 * 10 * 1000 * 1000);
-  };
-};
+//
+// isnull.c --- Check whether or not the UUID is null
+// Returns 1 if the uuid is the NULL uuid
+//
 
-/* get-current_time -- get time as 60 bit 100ns ticks since whenever.
-  Compensate for the fact that real clock resolution is
-  less than 100ns. */
-static void get_current_time(uuid_time_t * timestamp)
+int LIBNETXMS_EXPORTABLE uuid_is_null(uuid_t uu)
 {
-    uuid_time_t                time_now;
-    static uuid_time_t  time_last;
-    static WORD   uuids_this_tick;
-  static int                   inited = 0;
+       unsigned char   *cp;
+       int i;
 
-  if (!inited) 
-  {
-      get_system_time(&time_now);
-      uuids_this_tick = UUIDS_PER_TICK;
-      inited = 1;
-  };
+       for (i=0, cp = uu; i < 16; i++)
+               if (*cp++)
+                       return 0;
+       return 1;
+}
 
-    while (1) {
-        get_system_time(&time_now);
 
-      /* if clock reading changed since last UUID generated... */
-        if (time_last != time_now) {
-           /* reset count of uuids gen'd with this clock reading */
-            uuids_this_tick = 0;
-           break;
-      };
-        if (uuids_this_tick < UUIDS_PER_TICK) {
-           uuids_this_tick++;
-           break;
-      };
-      /* going too fast for our clock; spin */
-    };
-  /* add the count of uuids to low order bits of the clock reading */
-  *timestamp = time_now + uuids_this_tick;
-};
+//
+// Internal routine for packing UUID's
+//
 
-/* true_random -- generate a crypto-quality random number.
-   This sample doesn't do that. */
-static WORD true_random(void)
+void uuid_pack(struct uuid *uu, uuid_t ptr)
 {
-  static int inited = 0;
-  uuid_time_t time_now;
-
-  if (!inited) {
-      get_system_time(&time_now);
-      time_now = time_now/UUIDS_PER_TICK;
-      srand((unsigned int)(((time_now >> 32) ^ time_now)&0xffffffff));
-      inited = 1;
-  };
-
-    return (rand());
+       unsigned int    tmp;
+       unsigned char   *out = ptr;
+
+       tmp = uu->time_low;
+       out[3] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[2] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[1] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[0] = (unsigned char) tmp;
+       
+       tmp = uu->time_mid;
+       out[5] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[4] = (unsigned char) tmp;
+
+       tmp = uu->time_hi_and_version;
+       out[7] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[6] = (unsigned char) tmp;
+
+       tmp = uu->clock_seq;
+       out[9] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[8] = (unsigned char) tmp;
+
+       memcpy(out+10, uu->node, 6);
 }
 
-/* uuid_create_from_name -- create a UUID using a "name" from a "name
-space" */
-void LIBNETXMS_EXPORTABLE uuid_create_from_name(
-  uuid_t * uuid,        /* resulting UUID */
-  uuid_t nsid,          /* UUID to serve as context, so identical
-                           names from different name spaces generate
-                           different UUIDs */
-  void * name,          /* the name from which to generate a UUID */
-  int namelen           /* the length of the name */
-) {
-  MD5_CTX c;
-  unsigned char hash[16];
-  uuid_t net_nsid;      /* context UUID in network byte order */
-
-  /* put name space ID in network byte order so it hashes the same
-      no matter what endian machine we're on */
-  net_nsid = nsid;
-  htonl(net_nsid.time_low);
-  htons(net_nsid.time_mid);
-  htons(net_nsid.time_hi_and_version);
-
-  I_md5_init(&c);
-  I_md5_append(&c, (md5_byte_t *)&net_nsid, sizeof(uuid_t));
-  I_md5_append(&c, (md5_byte_t *)name, namelen);
-  I_md5_finish(&c, hash);
 
-  /* the hash is in network byte order at this point */
-  format_uuid_v3(uuid, hash);
-};
+//
+// Internal routine for unpacking UUID
+//
 
-/* format_uuid_v3 -- make a UUID from a (pseudo)random 128 bit number
-*/
-static void format_uuid_v3(uuid_t * uuid, unsigned char hash[16]) {
-    /* Construct a version 3 uuid with the (pseudo-)random number
-     * plus a few constants. */
-
-    memcpy(uuid, hash, sizeof(uuid_t));
-
-  /* convert UUID to local byte order */
-  ntohl(uuid->time_low);
-  ntohs(uuid->time_mid);
-  ntohs(uuid->time_hi_and_version);
-
-  /* put in the variant and version bits */
-    uuid->time_hi_and_version &= 0x0FFF;
-    uuid->time_hi_and_version |= (3 << 12);
-    uuid->clock_seq_hi_and_reserved &= 0x3F;
-    uuid->clock_seq_hi_and_reserved |= 0x80;
-};
-
-/* uuid_compare --  Compare two UUID's "lexically" and return
-       -1   u1 is lexically before u2
-        0   u1 is equal to u2
-        1   u1 is lexically after u2
-
-    Note:   lexical ordering is not temporal ordering!
-*/
-int LIBNETXMS_EXPORTABLE uuid_compare(const uuid_t *u1, const uuid_t *u2)
+void uuid_unpack(uuid_t in, struct uuid *uu)
 {
-  int i;
-
-#define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
-  CHECK(u1->time_low, u2->time_low);
-  CHECK(u1->time_mid, u2->time_mid);
-  CHECK(u1->time_hi_and_version, u2->time_hi_and_version);
-  CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved);
-  CHECK(u1->clock_seq_low, u2->clock_seq_low)
-  for (i = 0; i < 6; i++) {
-      if (u1->node[i] < u2->node[i])
-           return -1;
-      if (u1->node[i] > u2->node[i])
-      return 1;
-    }
-  return 0;
-};
+       unsigned char   *ptr = in;
+       unsigned int    tmp;
+
+       tmp = *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       uu->time_low = tmp;
+
+       tmp = *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       uu->time_mid = tmp;
+       
+       tmp = *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       uu->time_hi_and_version = tmp;
+
+       tmp = *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       uu->clock_seq = tmp;
+
+       memcpy(uu->node, ptr, 6);
+}
diff --git a/src/libnetxms/uuidP.h b/src/libnetxms/uuidP.h
new file mode 100644 (file)
index 0000000..ccbbf40
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * uuid.h -- private header file for uuids
+ * 
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU 
+ * Library General Public License.
+ * %End-Header%
+ */
+
+#ifndef _uuidP_h_
+#define _uuidP_h_
+
+#include <sys/types.h>
+
+#include <uuid.h>
+
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW  0x13814000
+
+struct uuid
+{
+       DWORD   time_low;
+       WORD    time_mid;
+       WORD    time_hi_and_version;
+       WORD    clock_seq;
+       BYTE    node[6];
+};
+
+
+/*
+ * prototypes
+ */
+void uuid_pack(struct uuid *uu, uuid_t ptr);
+void uuid_unpack(uuid_t in, struct uuid *uu);
+
+#endif
index c2b0bb7..073f8a5 100644 (file)
@@ -240,7 +240,7 @@ DWORD LIBNXCL_EXPORTABLE NXCConnect(TCHAR *pszServer, TCHAR *pszLogin,
 {
    struct sockaddr_in servAddr;
    CSCPMessage msg, *pResp;
-   BYTE szPasswordHash[SHA1_DIGEST_SIZE];
+//   BYTE szPasswordHash[SHA1_DIGEST_SIZE];
    DWORD dwRetCode = RCC_COMM_FAILURE;
    SOCKET hSocket;
    THREAD hThread;
@@ -344,7 +344,7 @@ DWORD LIBNXCL_EXPORTABLE NXCConnect(TCHAR *pszServer, TCHAR *pszLogin,
                         msg.SetId(pSession->CreateRqId());
                         msg.SetCode(CMD_LOGIN);
                         msg.SetVariable(VID_LOGIN_NAME, pszLogin);
-#ifdef UNICODE
+/*#ifdef UNICODE
                         char szMPasswd[64];
 
                             WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, 
@@ -353,7 +353,8 @@ DWORD LIBNXCL_EXPORTABLE NXCConnect(TCHAR *pszServer, TCHAR *pszLogin,
 #else
                         CalculateSHA1Hash((BYTE *)pszPassword, strlen(pszPassword), szPasswordHash);
 #endif
-                        msg.SetVariable(VID_PASSWORD, szPasswordHash, SHA1_DIGEST_SIZE);
+                        msg.SetVariable(VID_PASSWORD, szPasswordHash, SHA1_DIGEST_SIZE);*/
+                        msg.SetVariable(VID_PASSWORD, pszPassword);
                         msg.SetVariable(VID_CLIENT_INFO, pszClientInfo);
                         msg.SetVariable(VID_LIBNXCL_VERSION, NETXMS_VERSION_STRING);
                         GetOSVersionString(szBuffer);
index 6d7f6d2..86d9675 100644 (file)
@@ -11,12 +11,12 @@ libnxcore_la_SOURCES = acl.cpp agent.cpp actions.cpp admin.cpp alarm.cpp client.
                        locks.cpp lpp.cpp main.cpp map.cpp modules.cpp \
                        netinfo.cpp netobj.cpp netsrv.cpp node.cpp nortel.cpp \
                        np.cpp objects.cpp objtools.cpp package.cpp poll.cpp \
-                       rootobj.cpp script.cpp session.cpp sms.cpp snmp.cpp \
-                       snmptrap.cpp subnet.cpp syncer.cpp syslogd.cpp \
-                       template.cpp tools.cpp tracert.cpp uniroot.cpp \
-                       users.cpp vpnconn.cpp watchdog.cpp zone.cpp
+                       radius.cpp rootobj.cpp script.cpp session.cpp sms.cpp \
+                       snmp.cpp snmptrap.cpp subnet.cpp syncer.cpp \
+                       syslogd.cpp template.cpp tools.cpp tracert.cpp \
+                       uniroot.cpp users.cpp vpnconn.cpp watchdog.cpp zone.cpp
 libnxcore_la_LDFLAGS = -version-info $(LIBNXCORE_LIBRARY_VERSION)
 
 EXTRA_DIST = \
        nxcore.dsp nxcore.dsw \
-       nxcore.h
+       nxcore.h radius.h
index 880ea03..fd0ebd4 100644 (file)
@@ -330,6 +330,10 @@ SOURCE=.\poll.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\radius.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\rootobj.cpp
 # End Source File
 # Begin Source File
@@ -550,6 +554,10 @@ SOURCE=..\..\..\include\nxtools.h
 # End Source File
 # Begin Source File
 
+SOURCE=.\radius.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\include\rwlock.h
 # End Source File
 # Begin Source File
diff --git a/src/server/core/radius.cpp b/src/server/core/radius.cpp
new file mode 100644 (file)
index 0000000..601ae3a
--- /dev/null
@@ -0,0 +1,697 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
+**
+** RADIUS client
+** This code is based on uRadiusLib (C) Gary Wallis, 2006.
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: radius.cpp
+**
+**/
+
+#include "nxcore.h"
+#include "radius.h"
+
+
+//
+//     Add a pair at the end of a VALUE_PAIR list.
+//
+
+static void pairadd(VALUE_PAIR **first, VALUE_PAIR *newPair)
+{
+       VALUE_PAIR *i;
+
+       if (*first == NULL)
+   {
+               *first = newPair;
+               return;
+       }
+       for(i = *first; i->next; i = i->next)
+               ;
+       i->next = newPair;
+}
+
+
+//
+//     Release the memory used by a list of attribute-value pairs.
+//
+
+static void pairfree(VALUE_PAIR *pair)
+{
+       VALUE_PAIR      *next;
+
+       while(pair != NULL)
+   {
+               next = pair->next;
+               free(pair);
+               pair = next;
+       }
+}
+
+
+//
+//     Create a new pair.
+//
+
+VALUE_PAIR *paircreate(int attr, int type, char *pszName)
+{
+       VALUE_PAIR *vp;
+
+       if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL)
+               return NULL;
+       memset(vp, 0, sizeof(VALUE_PAIR));
+       vp->attribute = attr;
+       vp->op = PW_OPERATOR_EQUAL;
+       vp->type = type;
+   if (pszName != NULL)
+      strcpy(vp->name, pszName);
+   else
+               sprintf(vp->name, "Attr-%d", attr);
+       switch (vp->type)
+   {
+               case PW_TYPE_INTEGER:
+               case PW_TYPE_IPADDR:
+               case PW_TYPE_DATE:
+                       vp->length = 4;
+                       break;
+               default:
+                       vp->length = 0;
+                       break;
+       }
+
+       return vp;
+}
+
+
+//
+//     Generate AUTH_VECTOR_LEN worth of random data.
+//
+
+static void random_vector(unsigned char *vector)
+{
+       static int      did_srand = 0;
+       unsigned int    i;
+       int             n;
+
+#if defined(__linux__) || defined(BSD)
+       if (!did_srand)
+   {
+               /*
+                *      Try to use /dev/urandom to seed the
+                *      random generator. Not all *BSDs have it
+                *      but it doesn't hurt to try.
+                */
+               if ((n = open("/dev/urandom", O_RDONLY)) >= 0 &&
+                    read(n, (char *)&i, sizeof(i)) == sizeof(i)) {
+                       srandom(i);
+                       did_srand = 1;
+               }
+               if (n >= 0) close(n);
+       }
+
+       if (!did_srand) {
+               /*
+                *      Use more traditional way to seed.
+                */
+               srandom(time(NULL) + getpid());
+               did_srand = 1;
+       }
+
+       for (i = 0; i < AUTH_VECTOR_LEN;) {
+               n = random();
+               memcpy(vector, &n, sizeof(int));
+               vector += sizeof(int);
+               i += sizeof(int);
+       }
+#else
+
+#ifndef RAND_MAX
+#  define RAND_MAX 32768
+#endif
+       /*
+        *      Assume the system has neither /dev/urandom
+        *      nor random()/srandom() but just the old
+        *      rand() / srand() functions.
+        */
+       if (!did_srand)
+   {
+               char garbage[8];
+               i = time(NULL) + getpid();
+               for (n = 0; n < 8; n++) i+= (garbage[n] << i);
+               srand(i);
+               did_srand = 1;
+       }
+
+       for (i = 0; i < AUTH_VECTOR_LEN;) {
+               unsigned char c;
+               /*
+                *      Don't use the lower bits, also don't use
+                *      parts > RAND_MAX since they are zero.
+                */
+               n = rand() / (RAND_MAX / 256);
+               c = n;
+               memcpy(vector, &c, sizeof(c));
+               vector += sizeof(c);
+               i += sizeof(c);
+       }
+#endif
+}
+
+
+//
+//     Encode password.
+//
+//     Assume that "pwd_out" points to a buffer of at least AUTH_PASS_LEN bytes.
+//
+//     Returns new length.
+//
+
+static int rad_pwencode(char *pwd_in, char *pwd_out, char *secret, char *vector)
+{
+       char    passbuf[AUTH_PASS_LEN];
+       char    md5buf[256];
+       int     i, secretlen;
+
+       i = strlen(pwd_in);
+       memset(passbuf, 0, AUTH_PASS_LEN);
+       memcpy(passbuf, pwd_in, i > AUTH_PASS_LEN ? AUTH_PASS_LEN : i);
+
+       secretlen = strlen(secret);
+       if (secretlen + AUTH_VECTOR_LEN > 256)
+               secretlen = 256 - AUTH_VECTOR_LEN;
+       nx_strncpy(md5buf, secret, sizeof(md5buf));
+       memcpy(md5buf + secretlen, vector, AUTH_VECTOR_LEN);
+       CalculateMD5Hash((BYTE *)md5buf, secretlen + AUTH_VECTOR_LEN, (BYTE *)pwd_out);
+
+       for(i = 0; i < AUTH_PASS_LEN; i++)
+               *pwd_out++ ^= passbuf[i];
+
+       return AUTH_PASS_LEN;
+}
+
+
+/*
+ * Encrypt/decrypt string attributes, style 1.
+ *
+ * See RFC 2868, section 3.5 for details. Currently probably indeed 
+ * only useful for Tunnel-Password, but why make it a special case, 
+ * now we have a generic flags mechanism in place anyway...
+ *
+ * It's optimized a little for speed, but it could probably be better.
+ */
+
+#define        CLEAR_STRING_LEN        256     /* The RFC says it is */
+#define        SECRET_LEN              32      /* Max. in client.c */
+#define        MD5_LEN                 16      /* The algorithm specifies it */
+#define        SALT_LEN                2       /* The RFC says it is */
+
+static void encrypt_attr_style_1(char *secret, char *vector, VALUE_PAIR *vp)
+{
+       char clear_buf[CLEAR_STRING_LEN];
+       char work_buf[SECRET_LEN + AUTH_VECTOR_LEN + SALT_LEN];
+       char digest[MD5_LEN];
+       char *i,*o;
+       unsigned short salt;            /* salt in network order */
+       int clear_len;
+       int work_len;
+       int secret_len;
+       int n;
+
+       /* Create the string we'll actually be processing by copying up to 255
+          bytes of original cleartext, padding it with zeroes to a multiple of
+          16 bytes and inserting a length octet in front. */
+
+       /* Limit length */
+       clear_len = vp->length;
+       if (clear_len > CLEAR_STRING_LEN - 1) clear_len = CLEAR_STRING_LEN - 1;
+
+       /* Write the 'original' length byte and copy the buffer */
+       *clear_buf = clear_len;
+       memcpy(clear_buf + 1, vp->strvalue, clear_len);
+
+       /* From now on, the length byte is included with the byte count */
+       clear_len++;
+
+       /* Pad the string to a multiple of 1 chunk */
+       if (clear_len % MD5_LEN) {
+               memset(clear_buf+clear_len, 0, MD5_LEN - (clear_len % MD5_LEN));
+       }
+
+       /* Define input and number of chunks to process */
+       i = clear_buf;
+       clear_len = (clear_len + (MD5_LEN - 1)) / MD5_LEN;      
+
+       /* Define output and starting length */
+       o = vp->strvalue;
+       vp->length = sizeof(salt);
+
+       /*
+        * Fill in salt. Must be unique per attribute that uses it in the same 
+        * packet, and the most significant bit must be set - see RFC 2868.
+        *
+        * FIXME: this _may_ be too simple. For now we just take the vp 
+        * pointer, which should be different between attributes, xor-ed with 
+        * the first longword of the vector to make it a little more unique.
+        *
+        * Oh, and sizeof(long) always == sizeof(void*) in our part of the
+        * universe, right? (*BSD, Solaris, Linux, DEC Unix...)
+        */
+       salt = htons( ( ((long)vp ^ *(long *)vector) & 0xffff ) | 0x8000 );
+       memcpy(o, &salt, sizeof(salt));
+       o += sizeof(salt);
+
+       /* Create a first working buffer to calc the MD5 hash over */
+       secret_len = strlen(secret);    /* already limited by read_clients */
+       memcpy(work_buf, secret, secret_len);
+       memcpy(work_buf + secret_len, vector, AUTH_VECTOR_LEN);
+       memcpy(work_buf + secret_len + AUTH_VECTOR_LEN, &salt, sizeof(salt));
+       work_len = secret_len + AUTH_VECTOR_LEN + sizeof(salt);
+
+       for( ; clear_len; clear_len--)
+   {
+               /* Get the digest */
+               CalculateMD5Hash((BYTE *)work_buf, work_len, (BYTE *)digest);
+
+               /* Xor the clear text to get the output chunk and next buffer */
+               for(n = 0; n < MD5_LEN; n++)
+      {
+                       *(work_buf + secret_len + n) = *o++ = *i++ ^ digest[n];
+               }
+
+               /* This is the size of the next working buffer */
+               work_len = secret_len + MD5_LEN;
+
+               /* Increment the output length */
+               vp->length += MD5_LEN;
+       }
+}
+
+
+/*
+ * void encrypt_attr(char *secret, char *vector, VALUE_PAIR *vp);
+ *
+ * Encrypts vp->strvalue using style vp->flags.encrypt, possibly using 
+ * a request authenticator passed in vector and the shared secret.
+ *
+ * This should always succeed.
+ */
+
+static void encrypt_attr(char *secret, char *vector, VALUE_PAIR *vp)
+{
+       switch(vp->flags.encrypt)
+       {
+               case 0:
+                       /* Normal, cleartext. */
+                       break;
+
+               case 1:
+                       /* Tunnel Password (see RFC 2868, section 3.5). */
+                       encrypt_attr_style_1(secret, vector, vp);
+                       break;
+
+               default:
+                       /* Unknown style - don't send the cleartext! */
+                       vp->length = 19;
+                       memcpy(vp->strvalue, "UNKNOWN_ENCR_METHOD", vp->length);
+         WriteLog(MSG_RADIUS_UNKNOWN_ENCR_METHOD, EVENTLOG_ERROR_TYPE,
+                  "dd", vp->flags.encrypt, vp->attribute);
+       }
+}
+
+
+//
+//     Build radius packet. We assume that the header part
+//     of AUTH_HDR has already been filled in, we just
+//     fill auth->data with the A/V pairs from reply.
+//
+
+static int rad_build_packet(AUTH_HDR *auth, int auth_len,
+                                VALUE_PAIR *reply, char *msg, char *secret,
+                            char *vector, int *send_buffer)
+{
+       VALUE_PAIR              *vp;
+       u_short                 total_length;
+       u_char                  *ptr, *length_ptr;
+       char                    digest[16];
+       int                     vendorpec;
+       int                     len;
+       DWORD                   lvalue;
+
+       total_length = AUTH_HDR_LEN;
+
+       /*
+        *      Load up the configuration values for the user
+        */
+       ptr = auth->data;
+       for (vp = reply; vp; vp = vp->next)
+   {
+               /*
+                *      Check for overflow.
+                */
+               if (total_length + vp->length + 16 >= auth_len)
+                       break;
+
+               /*
+                *      This could be a vendor-specific attribute.
+                */
+               length_ptr = NULL;
+               if ((vendorpec = VENDOR(vp->attribute)) > 0)
+      {
+                       *ptr++ = PW_VENDOR_SPECIFIC;
+                       length_ptr = ptr;
+                       *ptr++ = 6;
+                       lvalue = htonl(vendorpec);
+                       memcpy(ptr, &lvalue, 4);
+                       ptr += 4;
+                       total_length += 6;
+               } 
+      else if (vp->attribute > 0xff)
+      {
+                       /*
+                        *      Ignore attributes > 0xff
+                        */
+                       continue;
+               }
+      else
+      {
+                       vendorpec = 0;
+      }
+
+#ifdef ATTRIB_NMC
+               if (vendorpec == VENDORPEC_USR) {
+                       lvalue = htonl(vp->attribute & 0xFFFF);
+                       memcpy(ptr, &lvalue, 4);
+                       total_length += 2;
+                       *length_ptr  += 2;
+                       ptr          += 4;
+               } else
+#endif
+               *ptr++ = (vp->attribute & 0xFF);
+
+               switch(vp->type)
+      {
+
+               case PW_TYPE_STRING:
+                       /*
+                        *      FIXME: this is just to make sure but
+                        *      should NOT be needed. In fact I have no
+                        *      idea if it is needed :)
+                        */
+                       if (vp->length == 0 && vp->strvalue[0] != 0)
+         {
+                               vp->length = strlen(vp->strvalue);
+                       }
+                       if (vp->length >= AUTH_STRING_LEN)
+         {
+                               vp->length = AUTH_STRING_LEN - 1;
+                       }
+
+                       /*
+                        * If the flags indicate a encrypted attribute, handle 
+                        * it here. I don't want to go through the reply list 
+                        * another time just for transformations like this.
+                        */
+                       if (vp->flags.encrypt)
+            encrypt_attr(secret, vector, vp);
+                       
+                       /*
+                        * vp->length is the length of the string value; len
+                        * is the length of the string field in the packet.
+                        * Normally, these are the same, but if a tag is
+                        * inserted only len will reflect this.
+                        *
+                        * Bug fixed: for tagged attributes with 'tunnel-pwd'
+                        * encryption, the tag is *always* inserted, regardless
+                        * of its value! (Another strange thing in RFC 2868...)
+                        */
+                       len = vp->length + (vp->flags.has_tag &&
+                                           (TAG_VALID(vp->flags.tag) ||
+                                            vp->flags.encrypt == 1));
+                           
+#ifdef ATTRIB_NMC
+                       if (vendorpec != VENDORPEC_USR)
+#endif
+                               *ptr++ = len + 2;
+                       if (length_ptr)
+            *length_ptr += len + 2;
+
+                       /* Insert the tag (sorry about the fast ugly test...) */
+                       if (len > vp->length) *ptr++ = vp->flags.tag;
+
+                       /* Use the original length of the string value */
+                       memcpy(ptr, vp->strvalue, vp->length);
+                       ptr += vp->length;              /* here too */
+                       total_length += len + 2;
+                       break;
+
+               case PW_TYPE_INTEGER:
+               case PW_TYPE_DATE:
+               case PW_TYPE_IPADDR:
+                       len = sizeof(DWORD) + (vp->flags.has_tag && 
+                                              vp->type != PW_TYPE_INTEGER);
+#ifdef ATTRIB_NMC
+                       if (vendorpec != VENDORPEC_USR)
+#endif
+                               *ptr++ = len + 2;
+                       if (length_ptr) *length_ptr += len + 2;
+                       
+                       /* Handle tags */
+                       lvalue = vp->lvalue;
+                       if (vp->flags.has_tag)
+         {
+                               if (vp->type == PW_TYPE_INTEGER)
+            {
+                                       /* Tagged integer: MSB is tag */
+                                       lvalue = (lvalue & 0xffffff) |
+                                                ((vp->flags.tag & 0xff) << 24);
+                               }
+                               else
+            {
+                                       /* Something else: insert the tag */
+                                       *ptr++ = vp->flags.tag;
+                               }
+                       }
+                       lvalue = htonl(lvalue);
+                       memcpy(ptr, &lvalue, sizeof(DWORD));
+                       ptr += sizeof(DWORD);
+                       total_length += len + 2;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       /*
+        *      Append the user message
+        *      FIXME: add multiple PW_REPLY_MESSAGEs if it
+        *      doesn't fit into one.
+        */
+       if (msg && msg[0])
+   {
+               len = strlen(msg);
+               if (len > 0 && len < AUTH_STRING_LEN-1) {
+                       *ptr++ = PW_REPLY_MESSAGE;
+                       *ptr++ = len + 2;
+                       memcpy(ptr, msg, len);
+                       ptr += len;
+                       total_length += len + 2;
+               }
+       }
+
+       auth->length = htons(total_length);
+
+       if (auth->code != PW_AUTHENTICATION_REQUEST &&
+           auth->code != PW_STATUS_SERVER)
+   {
+               /*
+                *      Append secret and calculate the response digest
+                */
+               len = strlen(secret);
+               if (total_length + len < auth_len)
+      {
+                       memcpy((char *)auth + total_length, secret, len);
+                       CalculateMD5Hash((BYTE *)auth, total_length + len, (BYTE *)digest);
+                       memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
+                       memset(send_buffer + total_length, 0, len);
+               }
+       }
+
+       return total_length;
+}
+
+
+//
+// Receive result from server
+//
+
+static int result_recv(DWORD host, WORD udp_port, char *buffer, int length,
+                       BYTE *vector, char *secretkey)
+{
+       AUTH_HDR        *auth;
+       int totallen, secretlen;
+       char reply_digest[AUTH_VECTOR_LEN];
+       char calc_digest[AUTH_VECTOR_LEN];
+   char szHostName[32];
+
+       auth = (AUTH_HDR *)buffer;
+       totallen = ntohs(auth->length);
+
+       if(totallen != length)
+       {
+               fprintf(stderr,"Received invalid reply length from server (want %d/ got %d)\n", totallen, length);
+               return 8;
+       }
+
+       // Verify the reply digest
+       memcpy(reply_digest, auth->vector, AUTH_VECTOR_LEN);
+       memcpy(auth->vector, vector, AUTH_VECTOR_LEN);
+       secretlen = strlen(secretkey);
+       memcpy(buffer + length, secretkey, secretlen);
+       CalculateMD5Hash((BYTE *)auth, length + secretlen, (BYTE *)calc_digest);
+
+       if(memcmp(reply_digest, calc_digest, AUTH_VECTOR_LEN) != 0)
+       {
+               fprintf(stderr,"Warning: Received invalid reply digest from server\n");
+       }
+
+   IpToStr(ntohl(host), szHostName);
+       DbgPrintf(AF_DEBUG_MISC, "RADIUS: Packet from host %s code=%d, id=%d, length=%d",
+                                szHostName, auth->code, auth->id, totallen);
+   return (auth->code == PW_AUTHENTICATION_REJECT) ? 1 : 0;
+}
+
+
+//
+// Authenticate user via RADIUS
+//
+
+int RadiusAuth(char *cLogin, char *cPasswd)
+{
+       AUTH_HDR *auth;
+       VALUE_PAIR *req, *vp;
+       DWORD server_ip, local_ip = 0;
+       struct sockaddr saremote;
+       struct sockaddr_in *sin;
+       struct timeval          tv;
+       fd_set readfds;
+       int port, salen, result, length, i;
+   int nRetries, nTimeout;
+   SOCKET sockfd;
+   int send_buffer[512];
+   int recv_buffer[512];
+   BYTE vector[AUTH_VECTOR_LEN];
+   char szServer[256], szSecret[256];
+
+   ConfigReadStr("RADIUSServer", szServer, 256, "localhost");
+   ConfigReadStr("RADIUSSecret", szSecret, 256, "netxms");
+   port = ConfigReadInt("RADIUSPort", PW_AUTH_UDP_PORT);
+   nRetries = ConfigReadInt("RADIUSNumRetries", 5);
+   nTimeout = ConfigReadInt("RADIUSTimeout", 3);
+
+       // Set up AUTH structure.
+       memset(send_buffer, 0, sizeof(send_buffer));
+       auth = (AUTH_HDR *)send_buffer;
+       auth->code = PW_AUTHENTICATION_REQUEST;
+       random_vector(auth->vector);
+       auth->id = getpid() & 255;
+
+       // Create attribute chain
+       req = NULL;
+
+   // User name
+   vp = paircreate(PW_USER_NAME, PW_TYPE_STRING, "User-Name");
+   strncpy(vp->strvalue, cLogin, AUTH_STRING_LEN);
+   vp->length = min(strlen(cLogin), AUTH_STRING_LEN);
+       pairadd(&req, vp);
+
+   // Password
+   vp = paircreate(PW_PASSWORD, PW_TYPE_STRING, "User-Password");
+       vp->length = rad_pwencode(cPasswd, vp->strvalue,
+                             szSecret, (char *)auth->vector);
+       pairadd(&req, vp);
+
+   // Resolve hostname.
+       server_ip = ResolveHostName(szServer);
+       if ((server_ip == INADDR_NONE) || (server_ip == INADDR_ANY))
+       {
+      DbgPrintf(AF_DEBUG_MISC, "RADIUS: cannot resolve server name \"%s\"", szServer);
+      pairfree(req);
+               return 3;
+       }
+
+       // Open a socket.
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0)
+       {
+               DbgPrintf(AF_DEBUG_MISC, "RADIUS: Cannot create socket");
+      pairfree(req);
+               return 5;
+       }
+
+       sin = (struct sockaddr_in *)&saremote;
+   memset(sin, 0, sizeof (saremote));
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = server_ip;
+       sin->sin_port = htons(port);
+
+       // Build final radius packet.
+       length = rad_build_packet(auth, sizeof(send_buffer),
+                                      req, NULL, szSecret, (char *)auth->vector, send_buffer);
+       memcpy(vector, auth->vector, sizeof(vector));
+   pairfree(req);
+
+       // Send the request we've built.
+       for(i = 0; i < nRetries; i++)
+       {
+               if (i > 0)
+         DbgPrintf(AF_DEBUG_MISC, "RADIUS: Re-sending request...");
+               sendto(sockfd, (char *)auth, length, 0,
+                           &saremote, sizeof(struct sockaddr_in));
+
+               FD_ZERO(&readfds);
+               FD_SET(sockfd, &readfds);
+               tv.tv_sec = nTimeout;
+               tv.tv_usec = 0;
+               if (select(sockfd + 1, &readfds, NULL, NULL, &tv) == 0)
+                       continue;
+
+               salen = sizeof(saremote);
+               result = recvfrom(sockfd, (char *)recv_buffer,
+                                      sizeof(recv_buffer), 0, &saremote, &salen);
+               if (result >= 0)
+                       break;
+
+               ThreadSleepMs(1000);
+       }
+
+       if (result > 0 && i < nRetries)
+       {
+               result = result_recv(sin->sin_addr.s_addr, sin->sin_port,
+                                         (char *)recv_buffer, result, vector,
+                           szSecret);
+       }
+   else
+   {
+      result = 7;
+   }
+
+       closesocket(sockfd);
+   WriteLog((result == 0) ? MSG_RADIUS_AUTH_SUCCESS : MSG_RADIUS_AUTH_FAILED,
+            EVENTLOG_INFORMATION_TYPE, "ss", cLogin, szServer);
+       return result;
+}
diff --git a/src/server/core/radius.h b/src/server/core/radius.h
new file mode 100644 (file)
index 0000000..1634205
--- /dev/null
@@ -0,0 +1,283 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
+**
+** RADIUS client
+** This code is based on uRadiusLib (C) Gary Wallis, 2006.
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: radius.h
+**
+**/
+
+#ifndef _RADIUS_H_
+#define _RADIUS_H_
+
+#define AUTH_VECTOR_LEN                16
+#define AUTH_PASS_LEN          16
+#define AUTH_STRING_LEN                254     /* 253 max + trailing zero */
+
+typedef struct pw_auth_hdr {
+       BYTE            code;
+       BYTE            id;
+       u_short         length;
+       BYTE            vector[AUTH_VECTOR_LEN];
+       BYTE            data[2];
+} AUTH_HDR;
+
+#define AUTH_HDR_LEN                20
+#define CHAP_VALUE_LENGTH           16
+
+#define PW_AUTH_UDP_PORT            1645
+#define PW_ACCT_UDP_PORT            1646
+
+#define VENDORPEC_USR               429
+#define VENDORPEC_CISTRON           8246
+
+#define PW_TYPE_STRING              0
+#define PW_TYPE_INTEGER             1
+#define PW_TYPE_IPADDR              2
+#define PW_TYPE_DATE                3
+
+
+#define PW_AUTHENTICATION_REQUEST   1
+#define PW_AUTHENTICATION_ACK       2
+#define PW_AUTHENTICATION_REJECT    3
+#define PW_ACCOUNTING_REQUEST       4
+#define PW_ACCOUNTING_RESPONSE         5
+#define PW_ACCOUNTING_STATUS        6
+#define PW_PASSWORD_REQUEST         7
+#define PW_PASSWORD_ACK             8
+#define PW_PASSWORD_REJECT          9
+#define PW_ACCOUNTING_MESSAGE       10
+#define PW_ACCESS_CHALLENGE         11
+#define PW_STATUS_SERVER            12
+#define PW_STATUS_CLIENT            13
+
+#define PW_USER_NAME                1
+#define PW_PASSWORD                 2
+#define PW_CHAP_PASSWORD            3
+#define PW_NAS_IP_ADDRESS           4
+#define PW_NAS_PORT                 5
+#define PW_SERVICE_TYPE             6
+#define PW_FRAMED_PROTOCOL          7
+#define PW_FRAMED_IP_ADDRESS        8
+#define PW_FRAMED_IP_NETMASK        9
+#define PW_FRAMED_ROUTING           10
+#define PW_FILTER_ID                11
+#define PW_FRAMED_MTU               12
+#define PW_FRAMED_COMPRESSION       13
+#define PW_LOGIN_IP_HOST            14
+#define PW_LOGIN_SERVICE            15
+#define PW_LOGIN_TCP_PORT           16
+#define PW_OLD_PASSWORD             17
+#define PW_REPLY_MESSAGE            18
+#define PW_CALLBACK_NUMBER          19
+#define PW_CALLBACK_ID              20
+#define PW_EXPIRATION               21
+#define PW_FRAMED_ROUTE             22
+#define PW_FRAMED_IPXNET            23
+#define PW_STATE                    24
+#define PW_CLASS                    25
+#define PW_VENDOR_SPECIFIC          26
+#define PW_SESSION_TIMEOUT          27
+#define PW_IDLE_TIMEOUT             28
+#define PW_CALLED_STATION_ID        30
+#define PW_CALLING_STATION_ID       31
+#define PW_PROXY_STATE              33
+
+#define PW_ACCT_STATUS_TYPE         40
+#define PW_ACCT_DELAY_TIME          41
+#define PW_ACCT_INPUT_OCTETS        42
+#define PW_ACCT_OUTPUT_OCTETS       43
+#define PW_ACCT_SESSION_ID          44
+#define PW_ACCT_AUTHENTIC           45
+#define PW_ACCT_SESSION_TIME        46
+#define PW_ACCT_INPUT_PACKETS       47
+#define PW_ACCT_OUTPUT_PACKETS         48
+
+#define PW_CHAP_CHALLENGE           60
+#define PW_NAS_PORT_TYPE            61
+#define PW_PORT_LIMIT               62
+#define PW_CONNECT_INFO             77
+
+/* Vendor specific attributes */
+#define PW_CISTRON_PROXIED_TO       ((VENDORPEC_CISTRON<<16)|11)
+
+/* Server side attributes */
+#define PW_FALL_THROUGH                        500
+#define PW_EXEC_PROGRAM                        502
+#define PW_EXEC_PROGRAM_WAIT           503
+
+#define PW_AUTHTYPE                    1000
+#define PW_PREFIX                      1003
+#define PW_SUFFIX                      1004
+#define PW_GROUP                       1005
+#define PW_CRYPT_PASSWORD              1006
+#define PW_CONNECT_RATE                        1007
+#define PW_USER_CATEGORY               1029
+#define PW_GROUP_NAME                  1030
+#define PW_HUNTGROUP_NAME              1031
+#define PW_SIMULTANEOUS_USE            1034
+#define PW_STRIP_USERNAME              1035
+#define PW_HINT                                1040
+#define PAM_AUTH_ATTR                  1041
+#define PW_LOGIN_TIME                  1042
+#define PW_REALM                       1045
+#define PW_CLIENT_IP_ADDRESS           1052
+
+/*
+ *     INTEGER TRANSLATIONS
+ */
+
+/*     USER TYPES      */
+
+#define        PW_LOGIN_USER                   1
+#define        PW_FRAMED_USER                  2
+#define        PW_DIALBACK_LOGIN_USER          3
+#define        PW_DIALBACK_FRAMED_USER         4
+
+/*     FRAMED PROTOCOLS        */
+
+#define        PW_PPP                          1
+#define        PW_SLIP                         2
+
+/*     FRAMED ROUTING VALUES   */
+
+#define        PW_NONE                         0
+#define        PW_BROADCAST                    1
+#define        PW_LISTEN                       2
+#define        PW_BROADCAST_LISTEN             3
+
+/*     FRAMED COMPRESSION TYPES        */
+
+#define        PW_VAN_JACOBSEN_TCP_IP          1
+
+/*     LOGIN SERVICES  */
+#define        PW_TELNET                       0
+#define        PW_RLOGIN                       1
+#define        PW_TCP_CLEAR                    2
+#define        PW_PORTMASTER                   3
+
+/*     AUTHENTICATION LEVEL    */
+#define PW_AUTHTYPE_LOCAL              0
+#define PW_AUTHTYPE_SYSTEM             1
+#define PW_AUTHTYPE_SECURID            2
+#define PW_AUTHTYPE_CRYPT              3
+#define PW_AUTHTYPE_REJECT             4
+#define PW_AUTHTYPE_MYSQL              252
+#define PW_AUTHTYPE_PAM                        253
+#define PW_AUTHTYPE_ACCEPT             254
+
+/*     PORT TYPES              */
+#define PW_NAS_PORT_ASYNC              0
+#define PW_NAS_PORT_SYNC               1
+#define PW_NAS_PORT_ISDN               2
+#define PW_NAS_PORT_ISDN_V120          3
+#define PW_NAS_PORT_ISDN_V110          4
+
+/*     STATUS TYPES    */
+
+#define PW_STATUS_START                        1
+#define PW_STATUS_STOP                 2
+#define PW_STATUS_ALIVE                        3
+#define PW_STATUS_ACCOUNTING_ON                7
+#define PW_STATUS_ACCOUNTING_OFF    8
+
+
+#define VENDOR(x) (x >> 16)
+
+
+ /*
+  *    This defines for tagged string attrs whether the tag
+  *    is actually inserted or not...! Stupid IMHO, but
+  *    that's what the draft says...
+  */
+
+#define TAG_VALID(x)   ((x) > 0 && (x) < 0x20)
+#define TAG_VALID_ZERO(x)   ((x) >= 0 && (x) < 0x20)
+
+
+/* 
+ *     This defines a TAG_ANY, the value for the tag if
+ *     a wildcard ('*') was specified in a check item.
+ */
+
+#define TAG_ANY                -128     /* SCHAR_MIN */
+
+
+typedef struct attr_flags
+{
+       char                    addport;        /* Add port to IP address */
+       char                    has_tag;        /* attribute allows tags */
+       signed char     tag;
+       char                    encrypt;        /* encryption method */
+       signed char     len_disp;       /* length displacement */
+} ATTR_FLAGS;
+
+
+typedef struct value_pair
+{
+       char                    name[40];
+       int                     attribute;
+       int                     type;
+       int                     length; /* of strvalue */
+       ATTR_FLAGS  flags;
+       DWORD                   lvalue;
+       int                     op;
+       char                    strvalue[AUTH_STRING_LEN];
+       int                     group;
+       struct value_pair       *next;
+} VALUE_PAIR;
+
+typedef struct auth_req {
+       DWORD                   ipaddr;
+       WORD                    udp_port;
+       BYTE                    id;
+       BYTE                    code;
+       BYTE                    vector[16];
+       BYTE                    secret[16];
+       BYTE                    username[AUTH_STRING_LEN];
+       VALUE_PAIR              *request;
+       int                     child_pid;      /* Process ID of child */
+       DWORD                   timestamp;
+       BYTE                    *data;          /* Raw received data */
+       int                     data_len;
+       VALUE_PAIR              *proxy_pairs;
+       /* Proxy support fields */
+       char                    realm[64];
+       int                     validated;      /* Already md5 checked */
+       DWORD                   server_ipaddr;
+       DWORD                   server_id;
+       VALUE_PAIR              *server_reply;  /* Reply from other server */
+       int                     server_code;    /* Reply code from other srv */
+       struct auth_req         *next;          /* Next active request */
+} AUTH_REQ;
+
+enum
+{
+  PW_OPERATOR_EQUAL = 0,       /* = */
+  PW_OPERATOR_NOT_EQUAL,       /* != */
+  PW_OPERATOR_LESS_THAN,       /* < */
+  PW_OPERATOR_GREATER_THAN,    /* > */
+  PW_OPERATOR_LESS_EQUAL,      /* <= */
+  PW_OPERATOR_GREATER_EQUAL,   /* >= */
+  PW_OPERATOR_SET,             /* := */
+  PW_OPERATOR_ADD,             /* += */
+  PW_OPERATOR_SUB,             /* -= */
+};
+
+#endif   /* _RADIUS_H_ */
index 355c2e9..516061c 100644 (file)
@@ -1032,8 +1032,8 @@ void ClientSession::SendServerInfo(DWORD dwRqId)
 void ClientSession::Login(CSCPMessage *pRequest)
 {
    CSCPMessage msg;
-   BYTE szPassword[SHA1_DIGEST_SIZE];
-   char szLogin[MAX_USER_NAME], szBuffer[32];
+   //BYTE szPassword[SHA1_DIGEST_SIZE];
+   char szLogin[MAX_USER_NAME], szPassword[MAX_DB_STRING], szBuffer[32];
    BOOL bChangePasswd;
    DWORD dwResult;
 
@@ -1057,7 +1057,8 @@ void ClientSession::Login(CSCPMessage *pRequest)
    {
       
       pRequest->GetVariableStr(VID_LOGIN_NAME, szLogin, MAX_USER_NAME);
-      pRequest->GetVariableBinary(VID_PASSWORD, szPassword, SHA1_DIGEST_SIZE);
+      pRequest->GetVariableStr(VID_PASSWORD, szPassword, MAX_DB_STRING);
+      //pRequest->GetVariableBinary(VID_PASSWORD, szPassword, SHA1_DIGEST_SIZE);
 
       dwResult = AuthenticateUser(szLogin, szPassword, &m_dwUserId,
                                   &m_dwSystemAccess, &bChangePasswd);
index e832b43..5376c7d 100644 (file)
 
 
 //
+// Externals
+//
+
+int RadiusAuth(char *pszLogin, char *pszPasswd);
+
+
+//
 // Global variables
 //
 
@@ -62,7 +69,7 @@ BOOL LoadUsers(void)
    DWORD i, iNumRows;
 
    // Load users
-   hResult = DBSelect(g_hCoreDB, "SELECT id,name,password,system_access,flags,full_name,description,grace_logins FROM users ORDER BY id");
+   hResult = DBSelect(g_hCoreDB, "SELECT id,name,password,system_access,flags,full_name,description,grace_logins,auth_method FROM users ORDER BY id");
    if (hResult == NULL)
       return FALSE;
 
@@ -85,6 +92,7 @@ BOOL LoadUsers(void)
       nx_strncpy(g_pUserList[i].szFullName, DBGetField(hResult, i, 5), MAX_USER_FULLNAME);
       nx_strncpy(g_pUserList[i].szDescription, DBGetField(hResult, i, 6), MAX_USER_DESCR);
       g_pUserList[i].nGraceLogins = DBGetFieldLong(hResult, i, 7);
+      g_pUserList[i].nAuthMethod = DBGetFieldLong(hResult, i, 8);
    }
 
    DBFreeResult(hResult);
@@ -106,6 +114,8 @@ BOOL LoadUsers(void)
       strcpy(g_pUserList[i].szDescription, "Built-in system administrator account");
       CalculateSHA1Hash((BYTE *)"netxms", 6, g_pUserList[i].szPassword);
       g_pUserList[i].nGraceLogins = MAX_GRACE_LOGINS;
+      g_pUserList[i].nAuthMethod = AUTH_NETXMS_PASSWORD;
+      uuid_generate(g_pUserList[i].guid);
       WriteLog(MSG_SUPERUSER_CREATED, EVENTLOG_WARNING_TYPE, NULL);
    }
 
@@ -302,11 +312,13 @@ void SaveUsers(DB_HANDLE hdb)
 // int pdwId.
 //
 
-DWORD AuthenticateUser(char *szName, BYTE *szPassword, DWORD *pdwId,
+DWORD AuthenticateUser(char *szName, char *szPassword, DWORD *pdwId,
                        DWORD *pdwSystemRights, BOOL *pbChangePasswd)
 {
    DWORD i, j;
    DWORD dwResult = RCC_ACCESS_DENIED;
+   BOOL bPasswordValid;
+   BYTE hash[SHA1_DIGEST_SIZE];
 
    MutexLock(m_hMutexUserAccess, INFINITE);
    for(i = 0; i < g_dwNumUsers; i++)
@@ -314,7 +326,23 @@ DWORD AuthenticateUser(char *szName, BYTE *szPassword, DWORD *pdwId,
       if ((!strcmp(szName, g_pUserList[i].szName)) &&
           (!(g_pUserList[i].wFlags & UF_DELETED)))
       {
-         if (!memcmp(szPassword, g_pUserList[i].szPassword, SHA1_DIGEST_SIZE))
+         switch(g_pUserList[i].nAuthMethod)
+         {
+            case AUTH_NETXMS_PASSWORD:
+               CalculateSHA1Hash((BYTE *)szPassword, strlen(szPassword), hash);
+               bPasswordValid = !memcmp(hash, g_pUserList[i].szPassword, SHA1_DIGEST_SIZE);
+               break;
+            case AUTH_RADIUS:
+               bPasswordValid = (RadiusAuth(szName, szPassword) == 0);
+               break;
+            default:
+               WriteLog(MSG_UNKNOWN_AUTH_METHOD, EVENTLOG_WARNING_TYPE, "ds",
+                        g_pUserList[i].nAuthMethod, szName);
+               bPasswordValid = FALSE;
+               break;
+         }
+
+         if (bPasswordValid)
          {
             if (!(g_pUserList[i].wFlags & UF_DISABLED))
             {
index 911d04d..9182de8 100644 (file)
@@ -67,6 +67,7 @@
 #include <dbdrv.h>
 #include <nms_cscp.h>
 #include <nms_util.h>
+#include <uuid.h>
 #include <nxsrvapi.h>
 #include <nxcscpapi.h>
 #include <nximage.h>
index 5ef2014..07a25ca 100644 (file)
 
 
 //
+// Authentication methods
+//
+
+#define AUTH_NETXMS_PASSWORD  0
+#define AUTH_RADIUS           1
+#define AUTH_RSA_SECUREID     2
+
+
+//
 // User structure
 //
 
@@ -45,6 +54,8 @@ typedef struct
    char szFullName[MAX_USER_FULLNAME];
    char szDescription[MAX_USER_DESCR];
    int nGraceLogins;
+   int nAuthMethod;
+   uuid_t guid;
 } NMS_USER;
 
 
@@ -61,6 +72,7 @@ typedef struct
    DWORD dwNumMembers;
    DWORD *pMembers;
    char szDescription[MAX_USER_DESCR];
+   uuid_t guid;
 } NMS_USER_GROUP;
 
 
@@ -112,7 +124,7 @@ BOOL LoadUsers(void);
 void SaveUsers(DB_HANDLE hdb);
 void AddUserToGroup(DWORD dwUserId, DWORD dwGroupId);
 BOOL CheckUserMembership(DWORD dwUserId, DWORD dwGroupId);
-DWORD AuthenticateUser(char *szName, BYTE *szPassword, DWORD *pdwId,
+DWORD AuthenticateUser(char *szName, char *szPassword, DWORD *pdwId,
                        DWORD *pdwSystemRights, BOOL *pbChangePasswd);
 void DumpUsers(CONSOLE_CTX pCtx);
 DWORD CreateNewUser(char *pszName, BOOL bIsGroup, DWORD *pdwId);
index f2c0858..aaf4951 100644 (file)
@@ -506,4 +506,34 @@ Language=English
 Error compiling library script %2 (ID: %1): %3
 .
 
+MessageId=
+SymbolicName=MSG_RADIUS_UNKNOWN_ENCR_METHOD
+Language=English
+RADIUS client error: encryption style %1 is not implemented (attribute %2)
+.
+
+MessageId=
+SymbolicName=MSG_RADIUS_DECR_FAILED
+Language=English
+RADIUS client error: decryption (style %1) failed for attribute %2
+.
+
+MessageId=
+SymbolicName=MSG_RADIUS_AUTH_SUCCESS
+Language=English
+User %1 was successfully authenticated by RADIUS server %2
+.
+
+MessageId=
+SymbolicName=MSG_RADIUS_AUTH_FAILED
+Language=English
+Authentication request for user %1 was rejected by RADIUS server %2
+.
+
+MessageId=
+SymbolicName=MSG_UNKNOWN_AUTH_METHOD
+Language=English
+Unsupported authentication method %1 requested for user %2
+.
+
 ;#endif