├── .gitignore ├── APIDOCS.txt ├── CONTRIBUTING.md ├── DataModel.txt ├── LICENSE ├── MUDlogo.jpg ├── Makefile.am ├── Makefile.in ├── README.md ├── aclocal.m4 ├── compile ├── config.guess ├── config.h.in ├── config.sub ├── configure ├── configure.ac ├── dbtools ├── Makefile.am ├── Makefile.in ├── mud_clobber_db └── mud_show_db ├── depcomp ├── examples ├── AAA-LLDP-DHCP │ ├── FR-diffs.txt │ ├── FR-setup.sh │ ├── README.md │ └── kick_radius.sh ├── certs_and_keys │ ├── README.md │ ├── env-80211ARintermediate.sh │ ├── env-root.sh │ ├── generate-ca-8021AR.sh │ ├── generate-ca-root.sh │ ├── generate-freeradius-cert.sh │ ├── generate-iDevID-8021AR.sh │ ├── openssl-8021ARintermediate.cnf │ ├── openssl-root.cnf │ └── run.sh ├── luminaire │ ├── README.md │ ├── README.txt │ ├── fs │ │ ├── Luminaire_150.json │ │ ├── Luminaire_150.p7s │ │ ├── MUD_FS_HTTPS_cert.pem │ │ ├── MUD_FS_HTTPS_key.pem │ │ ├── mud_https_server.py │ │ └── start_https_mudserver.sh │ ├── luminaire-cacert.pem │ ├── luminaire_conf.json │ └── test_client_output.txt └── mud_manager_conf.json ├── install-sh ├── ltmain.sh ├── m4 ├── libtool.m4 ├── ltoptions.m4 ├── ltsugar.m4 ├── ltversion.m4 └── lt~obsolete.m4 ├── missing ├── src ├── Makefile.am ├── Makefile.in ├── acl.h ├── acl_types.c ├── acl_types.h ├── cisco_dacl.c ├── cisco_dacl.h ├── civetweb │ ├── LICENSE.txt │ ├── civetweb.c │ ├── civetweb.h │ ├── handle_form.inl │ ├── md5.inl │ ├── sha1.inl │ └── timer.inl ├── log.c ├── log.h ├── mud_fs_client.c ├── mud_fs_client.h ├── mud_manager.c ├── mud_manager.h ├── mud_test_client.c ├── sessions.c └── sessions.h └── webui ├── .#style.css ├── Makefile.am ├── Makefile.in ├── edit.css ├── funcs.php ├── index.php ├── mm.js ├── mud-edit.php ├── mud-home.php ├── show-acl-policy.php ├── statics.php └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | .deps/ 2 | Makefile 3 | autom4te.cache/ 4 | config.h 5 | config.log 6 | config.status 7 | stamp-h1 8 | mongoose.c 9 | mongoose.h 10 | mud_manager 11 | mud_test_client 12 | *.o 13 | *~ 14 | civetweb/.dirstamp 15 | civetweb/.deps/ 16 | *.gz 17 | \#*\# 18 | -------------------------------------------------------------------------------- /APIDOCS.txt: -------------------------------------------------------------------------------- 1 | Here is API provided by MUD Controller: 2 | 3 | All request response are in JSON format. 4 | 5 | 1. /getaclname: 6 | parameters: MUD_URI contains the URI for the MUD File. (optional) 7 | MAC_ADDR contains MAC address of IoT device. (optional) 8 | NAS contains address of access swith (optional) 9 | SESS_ID contains session ID from AAA server (optional) 10 | 11 | This API must be called with either MUD_URI or MAC_ADDR, but can include both. 12 | 13 | Response: List of dacl names in Cisco AV pair format. It also includes the VLAN config, if MUD file 14 | has configured with inter device communication from same manufactuer. 15 | 16 | 2. /getaclpolicy: 17 | Parameters: ACL_NAME containts the DACL Name 18 | 19 | Response: List of ACE for the DACL name requested in Cisco AV pair format 20 | 21 | 22 | 3. /getmasauri: 23 | Parameters: MUD_URI contains URI for the MUD File 24 | 25 | Response: MASA_URI for the corresponding device. 26 | 27 | 4. /cfg_change 28 | 29 | Parameters: a JSON array: { "Update_URLs" : [ "URL1", "URL2"[,...]] 30 | 31 | Response: 200 or an error. 32 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Guidance on how to contribute 2 | 3 | > All contributions to this project will be released under the BSD-3 License. 4 | > By submitting a pull request or filing a bug, issue, or 5 | > feature request, you are agreeing to comply with this waiver of copyright interest. 6 | > Details can be found in our [LICENCE](LICENSE). 7 | 8 | 9 | There are two primary ways to help: 10 | - Using the issue tracker, and 11 | - Changing the code-base. 12 | 13 | 14 | ## Using the issue tracker 15 | 16 | Use the issue tracker to suggest feature requests, report bugs, and ask questions. 17 | This is also a great way to connect with the developers of the project as well 18 | as others who are interested in this solution. 19 | 20 | Use the issue tracker to find ways to contribute. Find a bug or a feature, mention in 21 | the issue that you will take on that effort, then follow the _Changing the code-base_ 22 | guidance below. 23 | 24 | 25 | ## Changing the code-base 26 | 27 | Generally speaking, you should fork this repository, make changes in your 28 | own fork, and then submit a pull-request. All new code should have associated unit 29 | tests that validate implemented features and the presence or lack of defects. 30 | Additionally, the code should follow any stylistic and architectural guidelines 31 | prescribed by the project. In the absence of such guidelines, mimic the styles 32 | and patterns in the existing code-base. 33 | -------------------------------------------------------------------------------- /DataModel.txt: -------------------------------------------------------------------------------- 1 | N.B. this file is subject to (rapid) change: 2 | 3 | There are three key collections: 4 | 5 | mudfiles: contains the MUD files themselves and most of the parsed 6 | fields in the top mud container, and the expiry of those 7 | entries. Also contains the controller mappings. 8 | Primary key: URI 9 | 10 | policies: contains policies directly tied to MUD URLs. Primary key 11 | is the URI. This collection also contains the VLAN_ID to 12 | be used with a policy. That's a bug. It should be 13 | normalized to the _id of a document in the vlans collection. 14 | 15 | vlans: contains available and assigned VLANs. 16 | The model is implemented is as follows: 17 | 18 | VLAN_ID: the VLAN # 19 | 20 | v4addrmask: a permitted ACE match for this VLAN 21 | v6addrmask: as above for v6. 22 | Owners: an array of either authorities or URLs. 23 | If Owners has no elements, it is available 24 | for assignment. 25 | 26 | Note that vlans can be populated from the config file with new 27 | free entries. 28 | 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Cisco and/or its affiliates. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /MUDlogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CiscoDevNet/MUD-Manager/f96502a384b4e10d2c1c862c31080e10b5b00f45/MUDlogo.jpg -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-2018 Cisco and/or its affiliates. 2 | # All rights reserved. 3 | 4 | AUTOMAKE_OPTIONS= foreign 5 | SUBDIRS= src dbtools webui 6 | ACLOCAL_AMFLAGS=-I m4 7 | 8 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand '-c -o'. 3 | 4 | scriptversion=2012-10-14.11; # UTC 5 | 6 | # Copyright (C) 1999-2014 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file lazy 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) LAZY, no conversion will 44 | # take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv/,$2, in 65 | *,$file_conv,*) 66 | ;; 67 | mingw/*) 68 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 69 | ;; 70 | cygwin/*) 71 | file=`cygpath -m "$file" || echo "$file"` 72 | ;; 73 | wine/*) 74 | file=`winepath -w "$file" || echo "$file"` 75 | ;; 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | # func_cl_dashL linkdir 82 | # Make cl look for libraries in LINKDIR 83 | func_cl_dashL () 84 | { 85 | func_file_conv "$1" 86 | if test -z "$lib_path"; then 87 | lib_path=$file 88 | else 89 | lib_path="$lib_path;$file" 90 | fi 91 | linker_opts="$linker_opts -LIBPATH:$file" 92 | } 93 | 94 | # func_cl_dashl library 95 | # Do a library search-path lookup for cl 96 | func_cl_dashl () 97 | { 98 | lib=$1 99 | found=no 100 | save_IFS=$IFS 101 | IFS=';' 102 | for dir in $lib_path $LIB 103 | do 104 | IFS=$save_IFS 105 | if $shared && test -f "$dir/$lib.dll.lib"; then 106 | found=yes 107 | lib=$dir/$lib.dll.lib 108 | break 109 | fi 110 | if test -f "$dir/$lib.lib"; then 111 | found=yes 112 | lib=$dir/$lib.lib 113 | break 114 | fi 115 | if test -f "$dir/lib$lib.a"; then 116 | found=yes 117 | lib=$dir/lib$lib.a 118 | break 119 | fi 120 | done 121 | IFS=$save_IFS 122 | 123 | if test "$found" != yes; then 124 | lib=$lib.lib 125 | fi 126 | } 127 | 128 | # func_cl_wrapper cl arg... 129 | # Adjust compile command to suit cl 130 | func_cl_wrapper () 131 | { 132 | # Assume a capable shell 133 | lib_path= 134 | shared=: 135 | linker_opts= 136 | for arg 137 | do 138 | if test -n "$eat"; then 139 | eat= 140 | else 141 | case $1 in 142 | -o) 143 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 144 | eat=1 145 | case $2 in 146 | *.o | *.[oO][bB][jJ]) 147 | func_file_conv "$2" 148 | set x "$@" -Fo"$file" 149 | shift 150 | ;; 151 | *) 152 | func_file_conv "$2" 153 | set x "$@" -Fe"$file" 154 | shift 155 | ;; 156 | esac 157 | ;; 158 | -I) 159 | eat=1 160 | func_file_conv "$2" mingw 161 | set x "$@" -I"$file" 162 | shift 163 | ;; 164 | -I*) 165 | func_file_conv "${1#-I}" mingw 166 | set x "$@" -I"$file" 167 | shift 168 | ;; 169 | -l) 170 | eat=1 171 | func_cl_dashl "$2" 172 | set x "$@" "$lib" 173 | shift 174 | ;; 175 | -l*) 176 | func_cl_dashl "${1#-l}" 177 | set x "$@" "$lib" 178 | shift 179 | ;; 180 | -L) 181 | eat=1 182 | func_cl_dashL "$2" 183 | ;; 184 | -L*) 185 | func_cl_dashL "${1#-L}" 186 | ;; 187 | -static) 188 | shared=false 189 | ;; 190 | -Wl,*) 191 | arg=${1#-Wl,} 192 | save_ifs="$IFS"; IFS=',' 193 | for flag in $arg; do 194 | IFS="$save_ifs" 195 | linker_opts="$linker_opts $flag" 196 | done 197 | IFS="$save_ifs" 198 | ;; 199 | -Xlinker) 200 | eat=1 201 | linker_opts="$linker_opts $2" 202 | ;; 203 | -*) 204 | set x "$@" "$1" 205 | shift 206 | ;; 207 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 208 | func_file_conv "$1" 209 | set x "$@" -Tp"$file" 210 | shift 211 | ;; 212 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 213 | func_file_conv "$1" mingw 214 | set x "$@" "$file" 215 | shift 216 | ;; 217 | *) 218 | set x "$@" "$1" 219 | shift 220 | ;; 221 | esac 222 | fi 223 | shift 224 | done 225 | if test -n "$linker_opts"; then 226 | linker_opts="-link$linker_opts" 227 | fi 228 | exec "$@" $linker_opts 229 | exit 1 230 | } 231 | 232 | eat= 233 | 234 | case $1 in 235 | '') 236 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 237 | exit 1; 238 | ;; 239 | -h | --h*) 240 | cat <<\EOF 241 | Usage: compile [--help] [--version] PROGRAM [ARGS] 242 | 243 | Wrapper for compilers which do not understand '-c -o'. 244 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 245 | arguments, and rename the output as expected. 246 | 247 | If you are trying to build a whole package this is not the 248 | right script to run: please start by reading the file 'INSTALL'. 249 | 250 | Report bugs to . 251 | EOF 252 | exit $? 253 | ;; 254 | -v | --v*) 255 | echo "compile $scriptversion" 256 | exit $? 257 | ;; 258 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) 259 | func_cl_wrapper "$@" # Doesn't return... 260 | ;; 261 | esac 262 | 263 | ofile= 264 | cfile= 265 | 266 | for arg 267 | do 268 | if test -n "$eat"; then 269 | eat= 270 | else 271 | case $1 in 272 | -o) 273 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 274 | # So we strip '-o arg' only if arg is an object. 275 | eat=1 276 | case $2 in 277 | *.o | *.obj) 278 | ofile=$2 279 | ;; 280 | *) 281 | set x "$@" -o "$2" 282 | shift 283 | ;; 284 | esac 285 | ;; 286 | *.c) 287 | cfile=$1 288 | set x "$@" "$1" 289 | shift 290 | ;; 291 | *) 292 | set x "$@" "$1" 293 | shift 294 | ;; 295 | esac 296 | fi 297 | shift 298 | done 299 | 300 | if test -z "$ofile" || test -z "$cfile"; then 301 | # If no '-o' option was seen then we might have been invoked from a 302 | # pattern rule where we don't need one. That is ok -- this is a 303 | # normal compilation that the losing compiler can handle. If no 304 | # '.c' file was seen then we are probably linking. That is also 305 | # ok. 306 | exec "$@" 307 | fi 308 | 309 | # Name of file we expect compiler to create. 310 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 311 | 312 | # Create the lock directory. 313 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 314 | # that we are using for the .o file. Also, base the name on the expected 315 | # object file name, since that is what matters with a parallel build. 316 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 317 | while true; do 318 | if mkdir "$lockdir" >/dev/null 2>&1; then 319 | break 320 | fi 321 | sleep 1 322 | done 323 | # FIXME: race condition here if user kills between mkdir and trap. 324 | trap "rmdir '$lockdir'; exit 1" 1 2 15 325 | 326 | # Run the compile. 327 | "$@" 328 | ret=$? 329 | 330 | if test -f "$cofile"; then 331 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 332 | elif test -f "${cofile}bj"; then 333 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 334 | fi 335 | 336 | rmdir "$lockdir" 337 | exit $ret 338 | 339 | # Local Variables: 340 | # mode: shell-script 341 | # sh-indentation: 2 342 | # eval: (add-hook 'write-file-hooks 'time-stamp) 343 | # time-stamp-start: "scriptversion=" 344 | # time-stamp-format: "%:y-%02m-%02d.%02H" 345 | # time-stamp-time-zone: "UTC" 346 | # time-stamp-end: "; # UTC" 347 | # End: 348 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_ARPA_INET_H 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_CJSON_H 8 | 9 | /* Define to 1 if you have the `clock_gettime' function. */ 10 | #undef HAVE_CLOCK_GETTIME 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_DLFCN_H 14 | 15 | /* Define to 1 if you have the `dup2' function. */ 16 | #undef HAVE_DUP2 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_FCNTL_H 20 | 21 | /* Define to 1 if you have the `fork' function. */ 22 | #undef HAVE_FORK 23 | 24 | /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ 25 | #undef HAVE_FSEEKO 26 | 27 | /* Define to 1 if you have the `gettimeofday' function. */ 28 | #undef HAVE_GETTIMEOFDAY 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_INTTYPES_H 32 | 33 | /* Define to 1 if you have the `cjson' library (-lcjson). */ 34 | #undef HAVE_LIBCJSON 35 | 36 | /* Define to 1 if you have the `cjson_utils' library (-lcjson_utils). */ 37 | #undef HAVE_LIBCJSON_UTILS 38 | 39 | /* Define to 1 if you have the `crypto' library (-lcrypto). */ 40 | #undef HAVE_LIBCRYPTO 41 | 42 | /* Define to 1 if you have the `curl' library (-lcurl). */ 43 | #undef HAVE_LIBCURL 44 | 45 | /* Define to 1 if you have the `dl' library (-ldl). */ 46 | #undef HAVE_LIBDL 47 | 48 | /* Define to 1 if you have the `m' library (-lm). */ 49 | #undef HAVE_LIBM 50 | 51 | /* Define to 1 if you have the `pthread' library (-lpthread). */ 52 | #undef HAVE_LIBPTHREAD 53 | 54 | /* Define to 1 if you have the `ssl' library (-lssl). */ 55 | #undef HAVE_LIBSSL 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #undef HAVE_LIMITS_H 59 | 60 | /* Define to 1 if you have the `localtime_r' function. */ 61 | #undef HAVE_LOCALTIME_R 62 | 63 | /* Define to 1 if you have the header file. */ 64 | #undef HAVE_MACH_MACH_H 65 | 66 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 67 | to 0 otherwise. */ 68 | #undef HAVE_MALLOC 69 | 70 | /* Define to 1 if you have the header file. */ 71 | #undef HAVE_MALLOC_H 72 | 73 | /* Define to 1 if you have the `memchr' function. */ 74 | #undef HAVE_MEMCHR 75 | 76 | /* Define to 1 if you have the `memmove' function. */ 77 | #undef HAVE_MEMMOVE 78 | 79 | /* Define to 1 if you have the header file. */ 80 | #undef HAVE_MEMORY_H 81 | 82 | /* Define to 1 if you have the `memset' function. */ 83 | #undef HAVE_MEMSET 84 | 85 | /* Define to 1 if you have the header file. */ 86 | #undef HAVE_NETDB_H 87 | 88 | /* Define to 1 if you have the header file. */ 89 | #undef HAVE_NETINET_IN_H 90 | 91 | /* Define to 1 if the system has the type `ptrdiff_t'. */ 92 | #undef HAVE_PTRDIFF_T 93 | 94 | /* Define to 1 if your system has a GNU libc compatible `realloc' function, 95 | and to 0 otherwise. */ 96 | #undef HAVE_REALLOC 97 | 98 | /* Define to 1 if you have the `rmdir' function. */ 99 | #undef HAVE_RMDIR 100 | 101 | /* Define to 1 if you have the `select' function. */ 102 | #undef HAVE_SELECT 103 | 104 | /* Define to 1 if you have the `socket' function. */ 105 | #undef HAVE_SOCKET 106 | 107 | /* Define to 1 if you have the header file. */ 108 | #undef HAVE_STDDEF_H 109 | 110 | /* Define to 1 if you have the header file. */ 111 | #undef HAVE_STDINT_H 112 | 113 | /* Define to 1 if you have the header file. */ 114 | #undef HAVE_STDLIB_H 115 | 116 | /* Define to 1 if you have the `strcasecmp' function. */ 117 | #undef HAVE_STRCASECMP 118 | 119 | /* Define to 1 if you have the `strchr' function. */ 120 | #undef HAVE_STRCHR 121 | 122 | /* Define to 1 if you have the `strcspn' function. */ 123 | #undef HAVE_STRCSPN 124 | 125 | /* Define to 1 if you have the `strdup' function. */ 126 | #undef HAVE_STRDUP 127 | 128 | /* Define to 1 if you have the `strerror' function. */ 129 | #undef HAVE_STRERROR 130 | 131 | /* Define to 1 if you have the header file. */ 132 | #undef HAVE_STRINGS_H 133 | 134 | /* Define to 1 if you have the header file. */ 135 | #undef HAVE_STRING_H 136 | 137 | /* Define to 1 if you have the `strndup' function. */ 138 | #undef HAVE_STRNDUP 139 | 140 | /* Define to 1 if you have the `strrchr' function. */ 141 | #undef HAVE_STRRCHR 142 | 143 | /* Define to 1 if you have the `strspn' function. */ 144 | #undef HAVE_STRSPN 145 | 146 | /* Define to 1 if you have the `strstr' function. */ 147 | #undef HAVE_STRSTR 148 | 149 | /* Define to 1 if you have the `strtol' function. */ 150 | #undef HAVE_STRTOL 151 | 152 | /* Define to 1 if you have the `strtoul' function. */ 153 | #undef HAVE_STRTOUL 154 | 155 | /* Define to 1 if you have the `strtoull' function. */ 156 | #undef HAVE_STRTOULL 157 | 158 | /* Define to 1 if you have the header file. */ 159 | #undef HAVE_SYS_SOCKET_H 160 | 161 | /* Define to 1 if you have the header file. */ 162 | #undef HAVE_SYS_STAT_H 163 | 164 | /* Define to 1 if you have the header file. */ 165 | #undef HAVE_SYS_TIME_H 166 | 167 | /* Define to 1 if you have the header file. */ 168 | #undef HAVE_SYS_TYPES_H 169 | 170 | /* Define to 1 if you have the `uname' function. */ 171 | #undef HAVE_UNAME 172 | 173 | /* Define to 1 if you have the header file. */ 174 | #undef HAVE_UNISTD_H 175 | 176 | /* Define to 1 if you have the `vfork' function. */ 177 | #undef HAVE_VFORK 178 | 179 | /* Define to 1 if you have the header file. */ 180 | #undef HAVE_VFORK_H 181 | 182 | /* Define to 1 if `fork' works. */ 183 | #undef HAVE_WORKING_FORK 184 | 185 | /* Define to 1 if `vfork' works. */ 186 | #undef HAVE_WORKING_VFORK 187 | 188 | /* Define to 1 if the system has the type `_Bool'. */ 189 | #undef HAVE__BOOL 190 | 191 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 192 | #undef LT_OBJDIR 193 | 194 | /* Name of package */ 195 | #undef PACKAGE 196 | 197 | /* Define to the address where bug reports for this package should be sent. */ 198 | #undef PACKAGE_BUGREPORT 199 | 200 | /* Define to the full name of this package. */ 201 | #undef PACKAGE_NAME 202 | 203 | /* Define to the full name and version of this package. */ 204 | #undef PACKAGE_STRING 205 | 206 | /* Define to the one symbol short name of this package. */ 207 | #undef PACKAGE_TARNAME 208 | 209 | /* Define to the home page for this package. */ 210 | #undef PACKAGE_URL 211 | 212 | /* Define to the version of this package. */ 213 | #undef PACKAGE_VERSION 214 | 215 | /* Define to 1 if you have the ANSI C header files. */ 216 | #undef STDC_HEADERS 217 | 218 | /* Version number of package */ 219 | #undef VERSION 220 | 221 | /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ 222 | #undef _LARGEFILE_SOURCE 223 | 224 | /* Define for Solaris 2.5.1 so the uint32_t typedef from , 225 | , or is not used. If the typedef were allowed, the 226 | #define below would cause a syntax error. */ 227 | #undef _UINT32_T 228 | 229 | /* Define for Solaris 2.5.1 so the uint64_t typedef from , 230 | , or is not used. If the typedef were allowed, the 231 | #define below would cause a syntax error. */ 232 | #undef _UINT64_T 233 | 234 | /* Define for Solaris 2.5.1 so the uint8_t typedef from , 235 | , or is not used. If the typedef were allowed, the 236 | #define below would cause a syntax error. */ 237 | #undef _UINT8_T 238 | 239 | /* Define to `int' if doesn't define. */ 240 | #undef gid_t 241 | 242 | /* Define to `__inline__' or `__inline' if that's what the C compiler 243 | calls it, or to nothing if 'inline' is not supported under any name. */ 244 | #ifndef __cplusplus 245 | #undef inline 246 | #endif 247 | 248 | /* Define to the type of a signed integer type of width exactly 64 bits if 249 | such a type exists and the standard includes do not define it. */ 250 | #undef int64_t 251 | 252 | /* Define to rpl_malloc if the replacement function should be used. */ 253 | #undef malloc 254 | 255 | /* Define to `long int' if does not define. */ 256 | #undef off_t 257 | 258 | /* Define to `int' if does not define. */ 259 | #undef pid_t 260 | 261 | /* Define to rpl_realloc if the replacement function should be used. */ 262 | #undef realloc 263 | 264 | /* Define to `unsigned int' if does not define. */ 265 | #undef size_t 266 | 267 | /* Define to `int' if does not define. */ 268 | #undef ssize_t 269 | 270 | /* Define to `int' if doesn't define. */ 271 | #undef uid_t 272 | 273 | /* Define to the type of an unsigned integer type of width exactly 16 bits if 274 | such a type exists and the standard includes do not define it. */ 275 | #undef uint16_t 276 | 277 | /* Define to the type of an unsigned integer type of width exactly 32 bits if 278 | such a type exists and the standard includes do not define it. */ 279 | #undef uint32_t 280 | 281 | /* Define to the type of an unsigned integer type of width exactly 64 bits if 282 | such a type exists and the standard includes do not define it. */ 283 | #undef uint64_t 284 | 285 | /* Define to the type of an unsigned integer type of width exactly 8 bits if 286 | such a type exists and the standard includes do not define it. */ 287 | #undef uint8_t 288 | 289 | /* Define as `fork' if `vfork' does not work. */ 290 | #undef vfork 291 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.69]) 5 | AC_INIT(MUD-Manager, 2.1dev, mud@cisco.com) 6 | AM_INIT_AUTOMAKE([foreign subdir-objects]) 7 | AC_OUTPUT(Makefile src/Makefile dbtools/Makefile webui/Makefile) 8 | LT_INIT 9 | AC_CONFIG_MACRO_DIRS([m4]) 10 | AC_CONFIG_SRCDIR([src/acl.h]) 11 | AC_CONFIG_HEADERS([config.h]) 12 | 13 | AC_ARG_WITH(composer, 14 | [AS_HELP_STRING([[--with-composer=location of composer]], 15 | [path to composer.])], 16 | [ 17 | if test "$withval" != "yes" ; then 18 | COMPOSER="$withval" 19 | fi 20 | ]) 21 | AC_PATH_PROG([COMPOSER],composer) 22 | AC_ARG_WITH(webui, 23 | [AS_HELP_STRING([[--with-webui=Web Directory]], 24 | [path to the web directory, no default if used.])], 25 | [ 26 | with_webui=true 27 | if test "$withval" != "yes" ; then 28 | WEBUI="$withval" 29 | else 30 | AC_MSG_FAILURE([No webui directory provided],1) 31 | fi 32 | if test x$COMPOSER = x; then 33 | AC_MSG_FAILURE([composer not found]) 34 | fi 35 | ]) 36 | AC_SUBST(WEBUI) 37 | AM_CONDITIONAL([BUILDUI],[test x$with_webui = xtrue ]) 38 | 39 | # Checks for programs. 40 | AC_PROG_CXX 41 | AC_PROG_CC 42 | AC_PROG_AWK 43 | AC_PROG_INSTALL 44 | AC_PROG_LN_S 45 | AC_PROG_CPP 46 | AC_PROG_MKDIR_P 47 | 48 | 49 | # Checks for libraries. 50 | 51 | AC_CHECK_LIB([cjson], [cJSON_Parse]) 52 | 53 | AC_CHECK_LIB([cjson_utils], [cJSONUtils_MergePatch]) 54 | 55 | AC_CHECK_LIB([crypto], [X509V3_get_d2i]) 56 | 57 | AC_CHECK_LIB([curl], [curl_easy_setopt]) 58 | 59 | AC_CHECK_LIB([dl], [dlopen]) 60 | 61 | AC_CHECK_LIB([m], [round]) 62 | 63 | AC_CHECK_LIB([pthread], [pthread_create]) 64 | 65 | AC_CHECK_LIB([ssl], [BIO_new_ssl]) 66 | 67 | 68 | if test "x$prefix" = "xNONE"; then 69 | prefix="/usr/local" 70 | fi 71 | 72 | if test "x$PKG_CONFIG_PATH" = x 73 | then 74 | export PKG_CONFIG_PATH="$prefix/lib/pkgconfig" 75 | else 76 | export PKG_CONFIG_PATH="$prefix/lib/pkgconfig:$PKG_CONFIG_PATH" 77 | fi 78 | 79 | PKG_CHECK_MODULES([MONGOC],[libmongoc-1.0],[],[]) 80 | 81 | # AC_SEARCH_LIBS(mongoc-1.0,[], [AC_ERROR[Could not find libmongoc-1.0]]) 82 | # AC_SEARCH_LIBS(libbson-1.0,[], [AC_ERROR[Could not find libbson-1.0]]) 83 | 84 | 85 | # Checks for header files. 86 | AC_CHECK_HEADERS([cJSON.h arpa/inet.h fcntl.h inttypes.h limits.h mach/mach.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h]) 87 | 88 | # Checks for typedefs, structures, and compiler characteristics. 89 | AC_CHECK_HEADER_STDBOOL 90 | AC_C_INLINE 91 | AC_TYPE_INT64_T 92 | AC_TYPE_OFF_T 93 | AC_TYPE_PID_T 94 | AC_TYPE_SIZE_T 95 | AC_TYPE_SSIZE_T 96 | AC_TYPE_UID_T 97 | AC_TYPE_UINT16_T 98 | AC_TYPE_UINT32_T 99 | AC_TYPE_UINT64_T 100 | AC_TYPE_UINT8_T 101 | AC_CHECK_TYPES([ptrdiff_t]) 102 | 103 | # Checks for library functions. 104 | AC_FUNC_FORK 105 | AC_FUNC_FSEEKO 106 | AC_FUNC_MALLOC 107 | AC_FUNC_REALLOC 108 | AC_CHECK_FUNCS([clock_gettime dup2 gettimeofday localtime_r memchr memmove memset rmdir select socket strcasecmp strchr strcspn strdup strerror strndup strrchr strspn strstr strtol strtoul strtoull uname]) 109 | 110 | AC_OUTPUT 111 | -------------------------------------------------------------------------------- /dbtools/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | 3 | bin_SCRIPTS=mud_show_db mud_clobber_db 4 | -------------------------------------------------------------------------------- /dbtools/mud_clobber_db: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FORCE="no" 4 | 5 | while getopts f c; do 6 | case "$c" in 7 | f) FORCE="yes"; shift;; 8 | *) echo "$0: $0 [-f]"; exit;; 9 | esac 10 | done 11 | 12 | if [ ${FORCE} != "yes" ]; then 13 | echo "WARNING: This will delete all MUD URL's and derived policy" 14 | echo " from the MUD Manager DB." 15 | while true; do 16 | read -p "Continue? Y/N" yn 17 | case $yn in 18 | [Yy]*) break;; 19 | [Nn]*) echo "Aborting."; exit;; 20 | *) echo "Please anser yes or no.";; 21 | esac 22 | done 23 | fi 24 | 25 | mongo mud_manager --eval "db.dropDatabase()" 26 | -------------------------------------------------------------------------------- /dbtools/mud_show_db: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Dump the MUD Manager collectiions. 5 | # 6 | # -v Verbose. Dumps the entire MUD file collection rather than 7 | # just the MUD URL. 8 | # 9 | 10 | USAGE="usage: $0: [-v]" 11 | ALL=0 12 | 13 | while getopts v c; do 14 | case "$c" in 15 | v)ALL=1; shift;; 16 | *)echo $USAGE; exit;; 17 | esac 18 | done 19 | 20 | echo "MUD FILE COLLECTION" 21 | 22 | if [ ${ALL} == 1 ]; then 23 | mongo mud_manager --eval "db.mudfile.find().forEach(printjson)" 24 | else 25 | mongo mud_manager --eval "db.mudfile.find().forEach(printjson)" | grep URI 26 | fi 27 | 28 | echo 29 | echo "MUD POLICIES COLLECTION" 30 | echo 31 | 32 | mongo mud_manager --eval "db.mud_policies.find().forEach(printjson)" 33 | 34 | echo 35 | echo "MUD MACADDR COLLECTION" 36 | echo 37 | 38 | mongo mud_manager --eval "db.macaddr.find().forEach(printjson)" 39 | 40 | echo 41 | echo "MUD VLANS COLLECTION" 42 | echo 43 | 44 | mongo mud_manager --eval "db.vlans.find().forEach(printjson)" 45 | -------------------------------------------------------------------------------- /examples/AAA-LLDP-DHCP/FR-diffs.txt: -------------------------------------------------------------------------------- 1 | --- dictionary 2019-06-27 16:34:16.713812240 -0400 2 | +++ dictionary 2019-06-27 16:35:35.506429685 -0400 3 | @@ -47,3 +47,16 @@ 4 | #ATTRIBUTE My-Local-String 3000 string 5 | #ATTRIBUTE My-Local-IPAddr 3001 ipaddr 6 | #ATTRIBUTE My-Local-Integer 3002 integer 7 | + 8 | + 9 | +ATTRIBUTE Cisco-MUD-URL 3000 string 10 | +ATTRIBUTE Url-Name 3001 string 11 | +ATTRIBUTE Url-Data 3002 string 12 | +ATTRIBUTE Url-DataType 3003 string 13 | +ATTRIBUTE Url-AddData 3004 string 14 | +ATTRIBUTE Url-AddDataType 3005 string 15 | +ATTRIBUTE Url-Nas 3006 string 16 | +ATTRIBUTE Url-NasType 3007 string 17 | +ATTRIBUTE Url-Sessid 3008 string 18 | +ATTRIBUTE Url-SessidType 3009 string 19 | +ATTRIBUTE TLS-Client-Cert-1.3.6.1.5.5.7.1.25 3010 string 20 | --- mods-available/rest 2019-06-27 16:34:16.709812209 -0400 21 | +++ mods-available/rest 2019-06-27 16:45:35.618997675 -0400 22 | @@ -46,7 +46,7 @@ 23 | # 24 | # If you wish to disable this pre-caching and reachability check, 25 | # comment out the configuration item below. 26 | - connect_uri = "http://127.0.0.1/" 27 | + connect_uri = "http://127.0.0.1:8000/" 28 | 29 | # 30 | # How long before new connection attempts timeout, defaults to 4.0 seconds. 31 | @@ -157,9 +157,14 @@ 32 | # 5xx server error no fail 33 | # xxx - no invalid 34 | authorize { 35 | - uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=authorize" 36 | - method = 'get' 37 | - tls = ${..tls} 38 | + # uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=authorize" 39 | + # method = 'get' 40 | + # tls = ${..tls} 41 | + body = 'json' 42 | + uri = "${..connect_uri}/%{Url-Name}" 43 | + data = '{"%{Url-DataType}":"%{Url-Data}"}' 44 | + force_to = 'json' 45 | + method = 'post' 46 | } 47 | authenticate { 48 | uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=authenticate" 49 | @@ -180,14 +185,24 @@ 50 | tls = ${..tls} 51 | } 52 | accounting { 53 | - uri = "${..connect_uri}/user/%{User-Name}/sessions/%{Acct-Unique-Session-ID}?action=accounting" 54 | - method = 'post' 55 | - tls = ${..tls} 56 | + # uri = "${..connect_uri}/user/%{User-Name}/sessions/%{Acct-Unique-Session-ID}?action=accounting" 57 | + # method = 'post' 58 | + # tls = ${..tls} 59 | + body = 'json' 60 | + uri = "${..connect_uri}/%{Url-Name}" 61 | + data = '{"%{Url-DataType}":"%{Url-Data}","%{Url-AddDataType}":"%{Url-AddData}","%{Url-NasType}":"%{Url-Nas}","%{Url-SessidType}":"%{Url-Sessid}"}' 62 | + force_to = 'json' 63 | + method = 'post' 64 | } 65 | post-auth { 66 | - uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=post-auth" 67 | - method = 'post' 68 | - tls = ${..tls} 69 | + # uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=post-auth" 70 | + # method = 'post' 71 | + # tls = ${..tls} 72 | + body = 'json' 73 | + uri = "${..connect_uri}/%{Url-Name}" 74 | + data = {"%{Url-DataType}":"%{Url-Data}"} 75 | + force_to = 'json' 76 | + method = 'post' 77 | } 78 | pre-proxy { 79 | uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=pre-proxy" 80 | --- mods-config/perl/example.pl 2019-06-27 16:34:16.693812083 -0400 81 | +++ mods-config/perl/example.pl 2019-06-27 16:46:47.735536757 -0400 82 | @@ -110,7 +110,125 @@ 83 | 84 | # Here's where your authorization code comes 85 | # You can call another function from here: 86 | - &test_call; 87 | + # &test_call; 88 | + 89 | + # Cisco-AVPair will be either an ARRAY (actually, a hash) or a 90 | + # single AV pair that is not an array. FreeRADIUS seems to send 91 | + # them differently. So we have to check if there's just one or not 92 | + # (as well as checking for none). 93 | + 94 | + if (not defined $RAD_REQUEST{'Cisco-AVPair'}) { 95 | + radiusd::radlog(L_DBG, "Cisco-AVPair not present"); 96 | + return RLM_MODULE_OK; 97 | + } 98 | + 99 | + if (ref($RAD_REQUEST{'Cisco-AVPair'}) eq 'ARRAY') { 100 | + # 101 | + # The array is passed within a hash value, and there does not 102 | + # seem to be a way to get its size! Note that statements such 103 | + # as 104 | + # my @values = values %RAD_REQUEST{'Cisco-AVPair'}; 105 | + # NO LONGER WORK as of Perl 5.28. 106 | + # 107 | + # So we loop through the array sequentially, assuming that 108 | + # (a) There will be no more than 40 Cisco-AVPair values, and 109 | + # (b) the "method=" statement is the last one. 110 | + # 111 | + for (my $i=0; $i <=40; $i++) { 112 | + radiusd::radlog(L_DBG, "C-AV: $RAD_REQUEST{'Cisco-AVPair'}[$i]"); 113 | + if ( $RAD_REQUEST{'Cisco-AVPair'}[$i] =~ /^method/ ) { 114 | + radiusd::radlog(L_DBG, "C-AV: End of List"); 115 | + last; 116 | + } 117 | + # 118 | + # This finds a "vendor specific" LLDP TLV (type 127). It 119 | + # may be a MUD URL, or may be some other TLV. To make sure 120 | + # it's a MUD URL, first check the IANA OUI and then find the 121 | + # 'http' string. 122 | + # 123 | + if ( $RAD_REQUEST{'Cisco-AVPair'}[$i] =~ /^lldp-tlv=\000\177/ ) { 124 | + my $value = $RAD_REQUEST{'Cisco-AVPair'}[$i]; 125 | + if ($value =~ /\000\000\136\001http/) { 126 | + my $loc = index($value, "http"); 127 | + $RAD_STATE{'Cisco-MUD-URL'} = 128 | + substr($value, $loc); 129 | + radiusd::radlog(L_DBG, "Returning MUD URL from LLDP TLV: $RAD_STATE{'Cisco-MUD-URL'}"); 130 | + last; 131 | + } 132 | + } 133 | + # 134 | + # This finds a DHCP Option 161, which should be a MUD URL. 135 | + # However, there are older uses of Option 161, so if there is 136 | + # no 'http' just skip it. 137 | + # 138 | + if ( $RAD_REQUEST{'Cisco-AVPair'}[$i] =~ 139 | + /^dhcp-option=\000\241/ ) { 140 | + my $value = $RAD_REQUEST{'Cisco-AVPair'}[$i]; 141 | + my $loc = index($value, "http"); 142 | + if ( $loc != 0 ) { 143 | + $RAD_STATE{'Cisco-MUD-URL'} = 144 | + substr($value, $loc); 145 | + radiusd::radlog(L_DBG, "Returning MUD URL from DHCP Option: $RAD_STATE{'Cisco-MUD-URL'}"); 146 | + last; 147 | + } 148 | + } 149 | + 150 | + } 151 | + } else { 152 | + # 153 | + # There was a single Cisco-AVPair attribute 154 | + # 155 | + radiusd::radlog(L_DBG, "C-AV: $RAD_REQUEST{'Cisco-AVPair'}"); 156 | + 157 | + # 158 | + # Check to see if it's a MUD URL in LLDP. 159 | + # 160 | + if ( $RAD_REQUEST{'Cisco-AVPair'} =~ /^lldp-tlv=\000\177/ ) { 161 | + my $value = $RAD_REQUEST{'Cisco-AVPair'}; 162 | + if ($value =~ /\000\000\136\001http/) { 163 | + my $loc = index($value, "http"); 164 | + $RAD_STATE{'Cisco-MUD-URL'} = substr($value, $loc); 165 | + radiusd::radlog(L_DBG, "Returning MUD URL from LLDP TLV: $RAD_STATE{'Cisco-MUD-URL'}"); 166 | + } 167 | + # 168 | + # Check to see if it's a MUD URL in DHCP. 169 | + # 170 | + } elsif ( $RAD_REQUEST{'Cisco-AVPair'} =~ /^dhcp-option=\000\241/ ){ 171 | + my $value = $RAD_REQUEST{'Cisco-AVPair'}; 172 | + my $loc = index($value, "http"); 173 | + if ( $loc != 0 ) { 174 | + $RAD_STATE{'Cisco-MUD-URL'} = substr($value, $loc); 175 | + radiusd::radlog(L_DBG, "Returning MUD URL from DHCP Option: $RAD_STATE{'Cisco-MUD-URL'}"); 176 | + } 177 | + } 178 | + } 179 | + 180 | + # 181 | + # Return 'User-Name' in the session data, preferably from the 182 | + # Accounting message. If there is no 'User-Name' in the # accounting 183 | + # message, then assume there was no authentication and fill it in from 184 | + # the # "Calling-Station-Id" to emulate MAB. 185 | + # 186 | + # NOTE: This value is used instead of the 'User-Name' determined by 187 | + # FreeRADIUS, which for an accounting message is also likely to be the 188 | + # 'User-Name' from the message. 189 | + # 190 | + if (defined $RAD_REQUEST{'User-Name'}) { 191 | + $RAD_STATE{'User-Name'} = $RAD_REQUEST{'User-Name'}; 192 | + radiusd::radlog(L_DBG, "Returning User-Name from 'User-Name': $RAD_STATE{'User-Name'}"); 193 | + 194 | + } elsif (defined $RAD_REQUEST{'Calling-Station-Id'}) { 195 | + # 196 | + # Remove the '-'s and change upper case to lower case. 197 | + # 198 | + my $username = $RAD_REQUEST{'Calling-Station-Id'} =~ s/-//gr; 199 | + $username = lc $username; 200 | + $RAD_STATE{'User-Name'} = $username; 201 | + radiusd::radlog(L_DBG, "Returning User-Name from 'Calling-Station-Id': $RAD_STATE{'User-Name'}"); 202 | + } else { 203 | + radiusd::radlog(L_DBG, "No User-Name returned"); 204 | + } 205 | + 206 | 207 | return RLM_MODULE_OK; 208 | } 209 | --- radiusd.conf 2019-06-27 16:34:16.713812240 -0400 210 | +++ radiusd.conf 2019-06-27 16:47:48.287988425 -0400 211 | @@ -389,6 +389,10 @@ 212 | # of those attacks 213 | # 214 | security { 215 | + 216 | + 217 | + allow_vulnerable_openssl = 'CVE-2016-6304' 218 | + 219 | # chroot: directory where the server does "chroot". 220 | # 221 | # The chroot is done very early in the process of starting 222 | --- sites-available/default 2019-06-27 16:34:16.721812304 -0400 223 | +++ sites-available/default 2019-06-27 16:51:41.761723365 -0400 224 | @@ -291,6 +291,33 @@ 225 | # 226 | filter_username 227 | 228 | + # The following lines are needed to recognize that the username 229 | + # provided by the Catalyst switch is the name of a dACL. 230 | + # 231 | + if (User-Name =~ /^(mud-)/) { 232 | + update control { 233 | + Auth-Type := Accept 234 | + } 235 | + } 236 | + 237 | + # The following lines allow FreeRADIUS to allow any "User-Name' that 238 | + # looks like a MAC address (i.e., Cisco "MAC Address Bypass (MAB)), 239 | + # so that we can accept the MUD URL sent in a AAA Accounting message 240 | + # later. 241 | + if ((User-Name =~ /^([0-9a-f]{12})/)) { 242 | + update { 243 | + &Url-Name := "getaclname" 244 | + &Url-DataType := "MAC_ADDR" 245 | + &Url-Data :="%{User-Name}" 246 | + } 247 | + rest 248 | + update control { 249 | + Auth-Type := Accept 250 | + } 251 | + } 252 | + 253 | + 254 | + 255 | # 256 | # Some broken equipment sends passwords with embedded zeros. 257 | # i.e. the debug output will show 258 | @@ -629,6 +656,29 @@ 259 | # If you don't use "radlast", you can delete this line. 260 | unix 261 | 262 | + # The perl module checks for a MUD URI as a Cisco-TLV. If there a TLV, 263 | + # it is returned in Cisco-MUD-URL (used for both X.509 certificate and 264 | + # LLDP use cases), and then the rest module is called to provide the 265 | + # MUD URI to the MUD controller and retreive ACL names built from the 266 | + # contents of the MUD file. 267 | + # 268 | + perl 269 | + if (&session-state:Cisco-MUD-URL) { 270 | + update { 271 | + &Url-Name := "getaclname" 272 | + &Url-DataType := "MAC_ADDR" 273 | + &Url-Data :="%{session-state:User-Name}" 274 | + &Url-AddDataType := "MUD_URI" 275 | + &Url-AddData :="%{session-state:Cisco-MUD-URL}" 276 | + &Url-NasType := "NAS" 277 | + &Url-Nas :="%{NAS-IP-Address}" 278 | + &Url-SessidType := "SESS_ID" 279 | + &Url-Sessid :="%{Acct-Session-Id}" 280 | + } 281 | + rest 282 | + } 283 | + 284 | + 285 | # 286 | # For Simultaneous-Use tracking. 287 | # 288 | @@ -705,6 +755,14 @@ 289 | # } 290 | # } 291 | 292 | + if (!&reply:State) { 293 | + update reply { 294 | + State := "0x%{randstr:16h}" 295 | + User-Name := "%{User-Name}" 296 | + Message-Authenticator := 0x00 297 | + } 298 | + } 299 | + 300 | # 301 | # For EAP-TTLS and PEAP, add the cached attributes to the reply. 302 | # The "session-state" attributes are automatically cached when 303 | @@ -723,9 +781,48 @@ 304 | &User-Name !* ANY 305 | } 306 | } 307 | - update { 308 | - &reply: += &session-state: 309 | - } 310 | +# update { 311 | +# &reply: += &session-state: 312 | +# } 313 | + 314 | + # This allows FreeRADIUS to accept a Cisco proprietary MUD URI RADIUS 315 | + # TLV -- NOT TESTED -- MIGHT PREPEND AN EXTRANEOUS "URI:" To URI VALUE 316 | + if (Cisco-MUD-URL) { 317 | + update { 318 | + &Url-Name := "getaclname" 319 | + &Url-AddDataType := "MUD_URI" 320 | + &Url-AddData :="%{Cisco-MUD-URL}" 321 | + &Url-NasType := "NAS" 322 | + &Url-Nas :="%{NAS-IP-Address}" 323 | + &Url-SessidType := "SESS_ID" 324 | + &Url-Sessid :="%{Acct-Session-Id}" 325 | + } 326 | + rest 327 | + 328 | + # This allows FreeFADIUS to recognize a MUD URI delivered in an X.509 329 | + # certificate. 330 | + } elsif (TLS-Client-Cert-1.3.6.1.5.5.7.1.25) { 331 | + update { 332 | + &Url-Name := "getaclname" 333 | + &Url-DataType := "MUD_URI" 334 | + &Url-Data :="%{TLS-Client-Cert-1.3.6.1.5.5.7.1.25}" 335 | + } 336 | + rest 337 | + 338 | + # This allows FreeRADIUS to recognize that a Cisco Catalyst switch has 339 | + # provided a dACL name and is asking for the contents of the dACL. 340 | + # This configuration uses the "rest" module again to forward the 341 | + # dACL name to the MUD controller, which will return the contents of 342 | + # the dACL. 343 | + # 344 | + } elsif (User-Name =~ /^(mud-)/) { 345 | + update { 346 | + &Url-Name := "getaclpolicy" 347 | + &Url-DataType := "ACL_NAME" 348 | + &Url-Data := "%{User-Name}" 349 | + } 350 | + rest 351 | + } 352 | 353 | # Get an address from the IP Pool. 354 | # main_pool 355 | -------------------------------------------------------------------------------- /examples/AAA-LLDP-DHCP/FR-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RADDB=/usr/local/etc/raddb 4 | PATCHDIR=`pwd` 5 | 6 | cd ${RADDB}; 7 | 8 | echo "Patching configuration files" 9 | patch -p0 <${PATCHDIR}/FR-diffs.txt 10 | 11 | echo "Adding necessary links" 12 | (cd mods-enabled; \ 13 | ln -s ../mods-available/rest rest; \ 14 | ln -s ../mods-available/perl perl) 15 | 16 | cd ${RADDB}; 17 | find . -name "*.rej" -delete 18 | 19 | -------------------------------------------------------------------------------- /examples/AAA-LLDP-DHCP/README.md: -------------------------------------------------------------------------------- 1 | # Example: AAA server calling the MUD Manager (MUD URI from LLDP, DHCP) 2 | 3 | MUD Manger can be used by a AAA server to discover authorization policy for 4 | constained devices. A NAS (e.g., Cisco Catalyst 9300) may deliver a MUD URI 5 | in a RADIUS accounting message as a Cisco-AVpair. This example shows how the 6 | FreeRADIUS AAA server can identify the MUD URI and provide it to the MUD i 7 | Manger using the MUD Manger RESTful APIs. The MUD Manager will first return 8 | names of "dynamic ACLs" to the NAS, after which the NAS will request the dACL 9 | contents by name. 10 | 11 | ## Dependencies 12 | 13 | FreeRADIUS 3.0.x. Although FreeRADIUS might be available in your distribution 14 | from a package (e.g., using apt-get), this example requires the REST module, 15 | which is not included by default. Download and configuration instructions are 16 | below. 17 | 18 | Perl 5. Earlier versions of Perl may also work but are untested. 19 | 20 | ## Making FreeRADIUS 21 | 22 | 1. Install dependancies for FreeRADIUS. 23 | 24 | ```bash 25 | sudo apt-get install -y libtalloc-dev libjson-c-dev libcurl4-gnutls-dev \ 26 | libperl-dev libkqueue-dev libssl-dev 27 | ``` 28 | 29 | 2. Download the source. Version 3.0.19 has been tested, but later versions are 30 | also likely to be fine. 31 | 32 | ```bash 33 | wget ftp://ftp.freeradius.org/pub/freeradius/freeradius-server-3.0.19.tar.gz 34 | tar -xf freeradius-server-3.0.19.tar.gz 35 | cd freeradius-server-3.0.19 36 | ``` 37 | 38 | 3. Make and install. 39 | 40 | ```bash 41 | ./configure --with-rest --with-json-c --with-perl 42 | make 43 | sudo make install 44 | ``` 45 | 46 | 4. Apply configuration patches found in this directory as the "root" user. 47 | 48 | ```bash 49 | sudo ./FR-setup.sh 50 | ``` 51 | 52 | **NOTE**: If you have an older version of OpenSSL, you may get a message from 53 | radiusd that the OpenSSL version has a vulnerabilty and should be 54 | updgraded. If you are working in a secure lab where you do not 55 | expect an attacker to take advantage of that vunlernability, you 56 | could instead add the following line within the "security" section of 57 | radiusd.conf: 58 | 59 | ``` bash 60 | allow_vulnerable_openssl = 'CVE-2016-6304' 61 | ``` 62 | 63 | 5. Edit the file `clients.conf` in the FreeRADIUS folder and add your NAS (e 64 | .g., Cisco Catalyst switch) as an authorized client to FreeRADIUS. Replace 65 | the IP address below with the IP address of your NAS, 66 | and use the "secret" configured on the NAS to talk to RADIUS servers. 67 | 68 | ``` 69 | client 192.168.126.142 { 70 | ipaddr = 192.168.126.142 71 | secret = cisco 72 | } 73 | ``` 74 | 75 | 7. Start up the MUD Manager (e.g., using the luminaire example). 76 | 77 | **NOTE**: If the MUD Manager is not listening on its socket, FreeRADIUS won't 78 | start properly. 79 | 80 | 7. Start the RADIUS server. It's helpful to start it in the foreground and 81 | watch the messages 82 | 83 | ```bash 84 | sudo radiusd -Xxx 85 | ``` 86 | 87 | 9. If you have installed the luminair example,the following script will 88 | verify that FreeRADIUS and the MUD Manager are communicating properly. 89 | 90 | ```bash 91 | ./kick_radius.sh 92 | ``` 93 | 94 | You should see something like the following displayed: 95 | 96 | ```bash 97 | Sent Accounting-Request Id XX from 0.0.0.0:57752 to 127.0.0.1:1813 length 118 98 | Received Accounting-Response Id XX from 127.0.0.1:1813 to 127.0.0.1:57752 length 73 99 | ``` 100 | 101 | The FreeRADIUS log should have lines something like the following: 102 | 103 | ```bash 104 | Debug: (0) Sent Accounting-Response Id XX from 127.0.0.1:1813 to 127.0.0.1:57752 length 0 105 | Debug: (0) Cisco-AVPair = "ACS:CiscoSecure-Defined-ACL=mud-21966-v4fr.in" 106 | Debug: (0) Finished request 107 | ``` 108 | -------------------------------------------------------------------------------- /examples/AAA-LLDP-DHCP/kick_radius.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # This test command will send a RADIUS accounting message containing a MUD URI 5 | # to a FreeRADIUS server. If the FreeRADIUS server is confgured with the MUD 6 | # Manager, and the MUD manager has a known MUD file server, then it should be 7 | # fetched and a single Cisco DACL returned. 8 | # 9 | # A successful return will have a message similar to the following in the 10 | # FreeRADIUS log: 11 | # 12 | # Debug: (0) Sent Accounting-Response Id XX from 127.0.0.1:1813 to 127.0.0.1:39143 length 0 13 | # Debug: (0) Cisco-AVPair = "ACS:CiscoSecure-Defined-ACL=mud-21966-v4fr.in" 14 | # Debug: (0) Finished request 15 | # 16 | 17 | radclient localhost:1813 acct cisco < 50 | Signature Algorithm: ecdsa-with-SHA256 51 | 30:45:02:21:00:85:08:f8:79:9d:59:bf:44:83:54:37:3d:76: 52 | 6e:6e:35:37:23:14:88:ed:95:8c:6d:dc:e3:5f:b8:79:9d:17: 53 | 8a:02:20:34:f1:96:16:8f:da:c8:37:34:cf:7a:77:80:33:d7: 54 | d2:95:5c:00:87:68:12:96:02:4a:2b:ae:cc:ab:8c:74:5e 55 | ``` 56 | 57 | 58 | ## Generating Certificate for FreeRadius 59 | 60 | To deploy the MUD, you need to generate a certificate for the FreeRADIUS as 61 | well. The generated certificates should then be copied to `raddb/certs` 62 | folder. You can do this by running the following file: 63 | 64 | ``` 65 | cd MUD-Manager/example/certs-and-keys 66 | ./generate-freeradius-cert.sh 67 | ``` 68 | 69 | This will generate the files named `server` in the `certs`, `csr` and 70 | `private` folders within `MUD-Manager-Vafa/examples/certs_and_keys/8021ARintermediate`. 71 | Next you have to copy the server file as well as the CA chain certificate to 72 | the FreeRADIUS folder. First make a backup of the `certs` folder in the 73 | `raddb` folder: 74 | ```bash 75 | sudo cp -r /usr/local/etc/raddb/certs /usr/local/etc/raddb/certs_bak 76 | ``` 77 | Then copy the certificates in the `raddb/certs`: 78 | ```bash 79 | cp MUD-Manager-Vafa/examples/certs_and_keys/8021ARintermediate/certs/ca-chain.cert.pem /usr/local/etc/raddb/certs/ca.pem 80 | cp MUD-Manager-Vafa/examples/certs_and_keys/8021ARintermediate/certs/server.cert.pem /usr/local/etc/raddb/certs/server.pem 81 | cp MUD-Manager-Vafa/examples/certs_and_keys/8021ARintermediate/private/server.key.pem /usr/local/etc/raddb/certs/server.key 82 | ``` 83 | 84 | 85 | 86 | **Important note:** After copying the `server` files to the `raddb/certs`, 87 | you should then modify the file `raddb/mods-available/eap`: 88 | 89 | - Find `private_key_password=` and set the password 90 | - Set the `private_key_file` file as follows: 91 | ``` 92 | private_key_file = ${certdir}/server.key 93 | ``` 94 | - Set the `certificate_file` file as follows: 95 | ``` 96 | certificate_file = ${certdir}/server.pem 97 | ``` 98 | 99 | 100 | 101 | ## wpa_supplicant configuration 102 | 103 | You can use the following configuration to connect to the wireless network: 104 | 105 | ``` 106 | ctrl_interface=/run/wpa_supplicant 107 | 108 | network={ 109 | ssid="yourwirelessssid" 110 | priority=1 111 | key_mgmt=WPA-EAP 112 | eap=TLS 113 | identity="user@example.org" 114 | client_cert="PATH/TO/CLIENT.pem" 115 | private_key="PATH/TO/CLIENT.key" 116 | private_key_passwd="PRIVATE KEY PASSWORD" 117 | } 118 | ``` 119 | 120 | note that wpa_supplicant cannot be used while the network manager service is 121 | using. To make sure that the network-manager service is not using the 122 | wpa_supplicant, you should add the interface to the `/etc/network/interfaces` 123 | . For instance if the interface is called `wlan0`, add the following to the 124 | end of the `/etc/network/interfaces` file: 125 | 126 | ``` 127 | allow-hotplug wlan0 128 | iface wlan0 inet dhcp 129 | wpa-conf /PATH/TO/WPA_SUPPLICANT.CONF 130 | ``` 131 | 132 | make sure the `iface wlan0` is not defined twice. Also, 133 | `/PATH/TO/WPA_SUPPLICANT.CONF` defines the path to the file in which you 134 | saved the above-mentioned configuration. After editing adding this 135 | information to the `/etc/network/interfaces`, you can take down the interface 136 | and bring it up again (as root) to intiate the connection: 137 | 138 | ``` 139 | ifdown wlan0 140 | ifup wlan0 141 | ``` 142 | 143 | **Note:** In case the wpa_spplicant did not connect successfully, there is a 144 | chance that the problem is caused by openssl version. Make sure that the TLS 145 | handshake is happening successfully: 146 | 147 | ``` 148 | (2) eap: Expiring EAP session with state 0x214e522020e35f22 149 | (2) eap: Finished EAP session with state 0x214e522020e35f22 150 | (2) eap: Previous EAP request found for state 0x214e522020e35f22, released from the list 151 | (2) eap: Peer sent packet with method EAP TLS (13) 152 | (2) eap: Calling submodule eap_tls to process data 153 | (2) eap_tls: Continuing EAP-TLS 154 | (2) eap_tls: [eaptls verify] = ok 155 | (2) eap_tls: Done initial handshake 156 | (2) eap_tls: (other): before SSL initialization 157 | (2) eap_tls: TLS_accept: before SSL initialization 158 | (2) eap_tls: TLS_accept: before SSL initialization 159 | (2) eap_tls: <<< recv TLS 1.3 [length 011c] 160 | (2) eap_tls: TLS_accept: SSLv3/TLS read client hello 161 | (2) eap_tls: >>> send TLS 1.2 [length 003d] 162 | (2) eap_tls: TLS_accept: SSLv3/TLS write server hello 163 | (2) eap_tls: >>> send TLS 1.2 [length 08e9] 164 | (2) eap_tls: TLS_accept: SSLv3/TLS write certificate 165 | (2) eap_tls: >>> send TLS 1.2 [length 014d] 166 | (2) eap_tls: TLS_accept: SSLv3/TLS write key exchange 167 | (2) eap_tls: >>> send TLS 1.2 [length 00d2] 168 | (2) eap_tls: TLS_accept: SSLv3/TLS write certificate request 169 | (2) eap_tls: >>> send TLS 1.2 [length 0004] 170 | (2) eap_tls: TLS_accept: SSLv3/TLS write server done 171 | (2) eap_tls: TLS_accept: Need to read more data: SSLv3/TLS write server done 172 | (2) eap_tls: TLS - In Handshake Phase 173 | (2) eap_tls: TLS - got 2914 bytes of data 174 | (2) eap_tls: [eaptls process] = handled 175 | (2) eap: Sending EAP Request (code 1) ID 174 length 1004 176 | (2) eap: EAP session adding &reply:State = 0x214e522023e05f22 177 | ``` 178 | 179 | an unsuccessful handshake might look partially like this: 180 | 181 | ``` 182 | (2) eap_peap: TLS_accept: before SSL initialization 183 | (2) eap_peap: TLS_accept: before SSL initialization 184 | (2) eap_peap: <<< recv UNKNOWN TLS VERSION ?0304? [length 011c] 185 | (2) eap_peap: TLS_accept: SSLv3/TLS read client hello 186 | (2) eap_peap: >>> send UNKNOWN TLS VERSION ?0304? [length 0058] 187 | (2) eap_peap: TLS_accept: SSLv3/TLS write server hello 188 | (2) eap_peap: >>> send UNKNOWN TLS VERSION ?0304? [length 0001] 189 | (2) eap_peap: TLS_accept: SSLv3/TLS write change cipher spec 190 | (2) eap_peap: TLS_accept: TLSv1.3 early data 191 | (2) eap_peap: TLS_accept: Need to read more data: TLSv1.3 early data 192 | ``` 193 | 194 | where some of the TLS versions are indicated as `UNKNOWN`. Installing 195 | Libressl instead of Openssl might fix this issue. 196 | -------------------------------------------------------------------------------- /examples/certs_and_keys/env-80211ARintermediate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################## 3 | # The content of this file is taken from the "Guide for building an ECC pki" 4 | # draft available at 5 | # https://datatracker.ietf.org/doc/draft-moskowitz-ecdsa-pki/?include_text=1 6 | ############################################################################## 7 | 8 | # Note: this files should be called from "generate-intermediate-ca.sh" 9 | # otherwise that script would not run completely and properly 10 | # 11 | # 12 | # 13 | # dir 14 | # Directory for certificate files 15 | # 16 | # cadir 17 | # 18 | # Directory for Root certificate files 19 | # 20 | # Format 21 | # File encoding: PEM or DER 22 | # At this time only PEM works 23 | # 24 | # sn 25 | # Serial Number length in bytes 26 | # For a public CA the range is 8 to 19 27 | 28 | export cadir=`pwd` 29 | 30 | export dir=$cadir/8021ARintermediate 31 | mkdir $dir 32 | cd $dir 33 | mkdir certs crl csr newcerts private 34 | chmod 700 private 35 | touch index.txt 36 | sn=8 # hex 8 is minimum, 19 is maximum 37 | echo 1000 > $dir/crlnumber 38 | 39 | # cd $dir 40 | export crlDP= 41 | # For CRL support use uncomment these: 42 | #crl=8021ARintermediate.crl.pem 43 | #crlurl=www.htt-consult.com/pki/$crl 44 | #export crlDP="URI:http://$crlurl" 45 | export default_crl_days=30 46 | export ocspIAI= 47 | # For OCSP support use uncomment these: 48 | #ocspurl=ocsp.htt-consult.com 49 | #export ocspIAI="OCSP;URI:http://$ocspurl" 50 | 51 | countryName="/C=US" 52 | stateOrProvinceName="/ST=IN" 53 | localityName="/L=Indiana University" 54 | organizationName="/O=Cisco" 55 | organizationalUnitName="/OU=Devices" 56 | commonName="/CN=802.1AR CA" 57 | DN=$countryName$stateOrProvinceName$localityName$organizationName 58 | DN=$DN$organizationalUnitName$commonName 59 | echo $DN 60 | export subjectAltName=email:whatever@happens.com 61 | echo $subjectAltName -------------------------------------------------------------------------------- /examples/certs_and_keys/env-root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################## 3 | # The content of this file is taken from the "Guide for building an ECC pki" 4 | # draft available at 5 | # https://datatracker.ietf.org/doc/draft-moskowitz-ecdsa-pki/?include_text=1 6 | ############################################################################## 7 | 8 | # Note: this files should be called from "generate-root-ca.sh" otherwise that 9 | # script would not run completely and properly 10 | # 11 | # 12 | # 13 | # cadir 14 | # 15 | # Directory for Root certificate files 16 | # 17 | # Format 18 | # File encoding: PEM or DER 19 | # At this time only PEM works 20 | # 21 | # sn 22 | # Serial Number length in bytes 23 | # For a public CA the range is 8 to 19 24 | 25 | export cadir=`pwd` 26 | 27 | export cadir=${cadir-/root/ca} 28 | export rootca=${cadir}/root 29 | export cfgdir=${cfgdir-$cadir} 30 | export intdir=${cadir}/intermediate 31 | export int1ardir=${cadir}/inter_1ar 32 | export format=pem 33 | export default_crl_days=65 34 | 35 | mkdir -p $cadir/certs 36 | mkdir -p $rootca 37 | (cd $rootca 38 | mkdir -p certs crl csr newcerts private 39 | chmod 700 private 40 | touch index.txt index.txt.attr 41 | if [ ! -f serial ]; then echo 00 >serial; fi 42 | ) 43 | 44 | sn=8 45 | 46 | # edit these to suit 47 | countryName="/C=US" 48 | stateOrProvinceName="/ST=IN" 49 | localityName="/L=Indiana University" 50 | organizationName="/O=Cisco" 51 | organizationalUnitName="/OU=Devices" 52 | commonName="/CN=Root CA" 53 | DN=$countryName$stateOrProvinceName$localityName 54 | export DN=$DN$organizationName$organizationalUnitName$commonName 55 | 56 | echo $DN 57 | export subjectAltName=email:whatever@happens.com 58 | 59 | export default_crl_days=2048 60 | 61 | 62 | -------------------------------------------------------------------------------- /examples/certs_and_keys/generate-ca-8021AR.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################## 3 | # The content of this file is taken from the "Guide for building an ECC pki" 4 | # draft available at 5 | # https://datatracker.ietf.org/doc/draft-moskowitz-ecdsa-pki/?include_text=1 6 | ############################################################################## 7 | 8 | 9 | 10 | # setting the environment for root certificate by sourcing env-intermediate.sh 11 | . ./env-80211ARintermediate.sh 12 | 13 | 14 | # Create passworded keypair file 15 | 16 | openssl genpkey -aes256 -algorithm ec\ 17 | -pkeyopt ec_paramgen_curve:prime256v1 \ 18 | -outform $format -pkeyopt ec_param_enc:named_curve\ 19 | -out $dir/private/8021ARintermediate.key.$format 20 | chmod 400 $dir/private/8021ARintermediate.key.$format 21 | openssl pkey -inform $format\ 22 | -in $dir/private/8021ARintermediate.key.$format -text -noout 23 | 24 | # Create the CSR 25 | 26 | openssl req -config $cadir/openssl-root.cnf\ 27 | -key $dir/private/8021ARintermediate.key.$format \ 28 | -keyform $format -outform $format -subj "$DN" -new -sha256\ 29 | -out $dir/csr/8021ARintermediate.csr.$format 30 | openssl req -text -noout -verify -inform $format\ 31 | -in $dir/csr/8021ARintermediate.csr.$format 32 | 33 | # Create 802.1AR Intermediate Certificate file 34 | # The following does NOT work for DER 35 | 36 | openssl rand -hex $sn > $dir/serial # hex 8 is minimum, 19 is maximum 37 | # Note 'openssl ca' does not support DER format 38 | openssl ca -config $cadir/openssl-root.cnf -days 3650\ 39 | -extensions v3_intermediate_ca -notext -md sha256\ 40 | -in $dir/csr/8021ARintermediate.csr.$format\ 41 | -out $dir/certs/8021ARintermediate.cert.pem 42 | 43 | chmod 444 $dir/certs/8021ARintermediate.cert.$format 44 | 45 | openssl verify -CAfile $cadir/certs/ca.cert.$format\ 46 | $dir/certs/8021ARintermediate.cert.$format 47 | 48 | openssl x509 -noout -text\ 49 | -in $dir/certs/8021ARintermediate.cert.$format 50 | 51 | # Create the certificate chain file 52 | 53 | cat $dir/certs/8021ARintermediate.cert.$format\ 54 | $cadir/certs/ca.cert.$format > $dir/certs/ca-chain.cert.$format 55 | chmod 444 $dir/certs/ca-chain.cert.$format -------------------------------------------------------------------------------- /examples/certs_and_keys/generate-ca-root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################## 3 | # The content of this file is taken from the "Guide for building an ECC pki" 4 | # draft available at 5 | # https://datatracker.ietf.org/doc/draft-moskowitz-ecdsa-pki/?include_text=1 6 | ############################################################################## 7 | 8 | 9 | # setting the environment for root certificate by sourcing env-root.sh 10 | . ./env-root.sh 11 | 12 | # Create passworded keypair file 13 | 14 | if [ ! -f $rootca/private/ca.key.$format ]; then 15 | echo GENERATING KEY 16 | openssl genpkey $pass -aes256 -algorithm ec\ 17 | -pkeyopt ec_paramgen_curve:prime256v1\ 18 | -outform $format -pkeyopt ec_param_enc:named_curve\ 19 | -out $rootca/private/ca.key.$format 20 | chmod 400 $rootca/private/ca.key.$format 21 | openssl pkey $passin -inform $format -in $rootca/private/ca.key.$format\ 22 | -text -noout 23 | fi 24 | 25 | # Create Self-signed Root Certificate file 26 | # 7300 days = 20 years; Intermediate CA is 10 years. 27 | 28 | echo GENERATING and SIGNING REQ 29 | openssl req -x509 -config $cfgdir/openssl-root.cnf $passin \ 30 | -set_serial 0x$(openssl rand -hex $sn)\ 31 | -keyform $format -outform $format\ 32 | -key $rootca/private/ca.key.$format -subj "$DN"\ 33 | -new -days 7300 -sha256 -extensions v3_ca\ 34 | -out $cadir/certs/ca.cert.$format 35 | 36 | # 37 | 38 | openssl x509 -inform $format -in $cadir/certs/ca.cert.$format -text -noout 39 | openssl x509 -purpose -inform $format -in $cadir/certs/ca.cert.$format -inform $format 40 | -------------------------------------------------------------------------------- /examples/certs_and_keys/generate-freeradius-cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################## 3 | # The content of this file is taken from the "Guide for building an ECC pki" 4 | # draft available at 5 | # https://datatracker.ietf.org/doc/draft-moskowitz-ecdsa-pki/?include_text=1 6 | ############################################################################## 7 | 8 | # setting the environment for root and intermediate certificate 9 | . ./env-root.sh 10 | . ./env-80211ARintermediate.sh 11 | 12 | 13 | DevID=server 14 | countryName= 15 | stateOrProvinceName= 16 | localityName= 17 | organizationName="/O=HTT Consulting" 18 | organizationalUnitName="/OU=Devices" 19 | commonName= 20 | serialNumber="/serialNumber=$DevID" 21 | DN=$countryName$stateOrProvinceName$localityName 22 | DN=$DN$organizationName$organizationalUnitName$commonName 23 | DN=$DN$serialNumber 24 | echo $DN 25 | 26 | # hwType is OID for HTT Consulting, devices, sensor widgets 27 | export hwType=1.3.6.1.4.1.6715.10.1 28 | export hwSerialNum=01020304 # Some hex 29 | export subjectAltName="otherName:1.3.6.1.5.5.7.8.4;SEQ:hmodname" 30 | echo $hwType - $hwSerialNum 31 | 32 | if [ ! -f $dir/private/$DevID.key.$format ]; then 33 | openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:prime256v1\ 34 | -pkeyopt ec_param_enc:named_curve\ 35 | -out $dir/private/$DevID.key.$format 36 | chmod 400 $dir/private/$DevID.key.$format 37 | fi 38 | 39 | openssl pkey -in $dir/private/$DevID.key.$format -text -noout 40 | openssl req -config $cfgdir/openssl-8021ARintermediate.cnf\ 41 | -key $dir/private/$DevID.key.$format \ 42 | -subj "$DN" -new -sha256 -out $dir/csr/$DevID.csr.$format 43 | 44 | openssl req -text -noout -verify\ 45 | -in $dir/csr/$DevID.csr.$format 46 | openssl asn1parse -i -in $dir/csr/$DevID.csr.pem 47 | 48 | openssl rand -hex $sn > $dir/serial # hex 8 is minimum, 19 is maximum 49 | # Note 'openssl ca' does not support DER format 50 | openssl ca -config $cfgdir/openssl-8021ARintermediate.cnf -days 375\ 51 | -extensions 8021ar_idevid -notext -md sha256 \ 52 | -in $dir/csr/$DevID.csr.$format\ 53 | -out $dir/certs/$DevID.cert.$format 54 | chmod 444 $dir/certs/$DevID.cert.$format 55 | 56 | openssl verify -CAfile $dir/certs/ca-chain.cert.$format\ 57 | $dir/certs/$DevID.cert.$format 58 | openssl x509 -noout -text -in $dir/certs/$DevID.cert.$format 59 | openssl asn1parse -i -in $dir/certs/$DevID.cert.pem 60 | 61 | -------------------------------------------------------------------------------- /examples/certs_and_keys/generate-iDevID-8021AR.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################## 3 | # The content of this file is taken from the "Guide for building an ECC pki" 4 | # draft available at 5 | # https://datatracker.ietf.org/doc/draft-moskowitz-ecdsa-pki/?include_text=1 6 | ############################################################################## 7 | 8 | # setting the environment for root certificate by sourcing env-intermediate.sh 9 | . ./env-root.sh 10 | . ./env-80211ARintermediate.sh 11 | 12 | 13 | DevID=Wt1234 14 | countryName= 15 | stateOrProvinceName= 16 | localityName= 17 | organizationName="/O=HTT Consulting" 18 | organizationalUnitName="/OU=Devices" 19 | commonName= 20 | serialNumber="/serialNumber=$DevID" 21 | DN=$countryName$stateOrProvinceName$localityName 22 | DN=$DN$organizationName$organizationalUnitName$commonName 23 | DN=$DN$serialNumber 24 | echo $DN 25 | 26 | # hwType is OID for HTT Consulting, devices, sensor widgets 27 | export hwType=1.3.6.1.4.1.6715.10.1 28 | export hwSerialNum=01020304 # Some hex 29 | export subjectAltName="otherName:1.3.6.1.5.5.7.8.4;SEQ:hmodname" 30 | echo $hwType - $hwSerialNum 31 | 32 | if [ ! -f $dir/private/$DevID.key.$format ]; then 33 | openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:prime256v1\ 34 | -pkeyopt ec_param_enc:named_curve\ 35 | -out $dir/private/$DevID.key.$format 36 | chmod 400 $dir/private/$DevID.key.$format 37 | fi 38 | 39 | openssl pkey -in $dir/private/$DevID.key.$format -text -noout 40 | openssl req -config $cfgdir/openssl-8021ARintermediate.cnf\ 41 | -key $dir/private/$DevID.key.$format \ 42 | -subj "$DN" -new -sha256 -out $dir/csr/$DevID.csr.$format 43 | 44 | openssl req -text -noout -verify\ 45 | -in $dir/csr/$DevID.csr.$format 46 | openssl asn1parse -i -in $dir/csr/$DevID.csr.pem 47 | 48 | openssl rand -hex $sn > $dir/serial # hex 8 is minimum, 19 is maximum 49 | # Note 'openssl ca' does not support DER format 50 | openssl ca -config $cfgdir/openssl-8021ARintermediate.cnf -days 375\ 51 | -extensions 8021ar_idevid -notext -md sha256 \ 52 | -in $dir/csr/$DevID.csr.$format\ 53 | -out $dir/certs/$DevID.cert.$format 54 | chmod 444 $dir/certs/$DevID.cert.$format 55 | 56 | openssl verify -CAfile $dir/certs/ca-chain.cert.$format\ 57 | $dir/certs/$DevID.cert.$format 58 | openssl x509 -noout -text -in $dir/certs/$DevID.cert.$format 59 | openssl asn1parse -i -in $dir/certs/$DevID.cert.pem 60 | 61 | -------------------------------------------------------------------------------- /examples/certs_and_keys/openssl-8021ARintermediate.cnf: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # The content of this file is taken from the "Guide for building an ECC pki" 3 | # draft available at 4 | # https://datatracker.ietf.org/doc/draft-moskowitz-ecdsa-pki/?include_text=1 5 | ############################################################################## 6 | 7 | 8 | # OpenSSL 8021ARintermediate CA configuration file. 9 | # Copy to `$dir/openssl-8021ARintermediate.cnf`. 10 | # 11 | # Remove the crlDistributionPoints to drop CRL support and 12 | # authorityInfoAccess to drop OCSP support. 13 | 14 | [ ca ] 15 | # `man ca` 16 | default_ca = CA_default 17 | 18 | [ CA_default ] 19 | # Directory and file locations. 20 | # dir = /root/ca/8021ARintermediate 21 | dir = $ENV::dir 22 | cadir = $ENV::cadir 23 | format = $ENV::format 24 | 25 | certs = $dir/certs 26 | crl_dir = $dir/crl 27 | new_certs_dir = $dir/newcerts 28 | database = $dir/index.txt 29 | serial = $dir/serial 30 | RANDFILE = $dir/private/.rand 31 | 32 | # The root key and root certificate. 33 | private_key = $dir/private/8021ARintermediate.key.$format 34 | certificate = $dir/certs/8021ARintermediate.cert.$format 35 | 36 | # For certificate revocation lists. 37 | crlnumber = $dir/crlnumber 38 | crl = $dir/crl/ca.crl.pem 39 | crl_extensions = crl_ext 40 | default_crl_days = $ENV::default_crl_days 41 | 42 | # SHA-1 is deprecated, so use SHA-2 instead. 43 | default_md = sha256 44 | 45 | name_opt = ca_default 46 | cert_opt = ca_default 47 | default_enddate = 99991231235959Z # per IEEE 802.1AR 48 | preserve = no 49 | policy = policy_loose 50 | copy_extensions = copy 51 | 52 | [ policy_strict ] 53 | # The root CA should only sign 8021ARintermediate certificates that match. 54 | # See the POLICY FORMAT section of `man ca`. 55 | countryName = match 56 | stateOrProvinceName = match 57 | organizationName = match 58 | organizationalUnitName = optional 59 | commonName = optional 60 | 61 | [ policy_loose ] 62 | # Allow the 8021ARintermediate CA to sign a more diverse range of certificates. 63 | # See the POLICY FORMAT section of the `ca` man page. 64 | countryName = optional 65 | stateOrProvinceName = optional 66 | localityName = optional 67 | organizationName = optional 68 | organizationalUnitName = optional 69 | commonName = optional 70 | serialNumber = optional 71 | 72 | [ req ] 73 | # Options for the `req` tool (`man req`). 74 | default_bits = 2048 75 | distinguished_name = req_distinguished_name 76 | string_mask = utf8only 77 | req_extensions = req_ext 78 | 79 | # SHA-1 is deprecated, so use SHA-2 instead. 80 | default_md = sha256 81 | 82 | # Extension to add when the -x509 option is used. 83 | x509_extensions = v3_ca 84 | 85 | [ req_distinguished_name ] 86 | # See . 87 | countryName = Country Name (2 letter code) 88 | stateOrProvinceName = State or Province Name 89 | localityName = Locality Name 90 | 0.organizationName = Organization Name 91 | organizationalUnitName = Organizational Unit Name 92 | commonName = Common Name 93 | serialNumber = Device Serial Number 94 | 95 | # Optionally, specify some defaults. 96 | 0.organizationName_default = HTT Consulting 97 | organizationalUnitName_default = Devices 98 | 99 | [ req_ext ] 100 | subjectAltName = $ENV::subjectAltName 101 | 102 | [ hmodname ] 103 | hwType = OID:$ENV::hwType 104 | hwSerialNum = FORMAT:HEX,OCT:$ENV::hwSerialNum 105 | 106 | [ v3_ca ] 107 | # Extensions for a typical CA (`man x509v3_config`). 108 | subjectKeyIdentifier = hash 109 | authorityKeyIdentifier = keyid:always,issuer 110 | basicConstraints = critical, CA:true 111 | keyUsage = critical, digitalSignature, cRLSign, keyCertSign 112 | 113 | [ v3_8021ARintermediate_ca ] 114 | # Extensions for a typical 115 | # 8021ARintermediate CA (`man x509v3_config`). 116 | subjectKeyIdentifier = hash 117 | authorityKeyIdentifier = keyid:always,issuer 118 | basicConstraints = critical, CA:true, pathlen:0 119 | # keyUsage = critical, digitalSignature, cRLSign, keyCertSign 120 | keyUsage = critical, cRLSign, keyCertSign 121 | 122 | [ 8021ar_idevid ] 123 | # Extensions for IEEE 802.1AR iDevID 124 | # certificates (`man x509v3_config`). 125 | basicConstraints = CA:FALSE 126 | authorityKeyIdentifier = keyid,issuer:always 127 | keyUsage = critical, digitalSignature, keyEncipherment 128 | # uncomment the following if the ENV variables set 129 | # crlDistributionPoints = $ENV::crlDP 130 | # authorityInfoAccess = $ENV::ocspIAI 131 | 132 | [ crl_ext ] 133 | # Extension for CRLs (`man x509v3_config`). 134 | authorityKeyIdentifier=keyid:always 135 | 136 | [ ocsp ] 137 | # Extension for OCSP signing certificates (`man ocsp`). 138 | basicConstraints = CA:FALSE 139 | subjectKeyIdentifier = hash 140 | authorityKeyIdentifier = keyid,issuer 141 | keyUsage = critical, digitalSignature 142 | extendedKeyUsage = critical, OCSPSigning 143 | 144 | 145 | [ mud_signers ] 146 | # This section is for inclusion of the MUD-signer extension in a 147 | # device certificate. It represents an X.509 Name, as defined in 148 | # RFC 5280 that is referenced in the Subject Name of the signing 149 | # certificate of the MUD file signature (described in sections 150 | # 11 and 13 of RFC 8520). 151 | # 152 | # N.B. this form may vary somewhat based on the CHOICE of Name 153 | # used in a certificate. The way this is handled is as follows: 154 | # 155 | # Use the dumpasn1 to determine the appropriate structure. For 156 | # example, the following output represents the name 157 | # "C = CH, emailAddress = ascertia@ofcourseimright.com, CN = Eliot Lear" 158 | # 159 | # [...] 160 | # 147 79: SEQUENCE { 161 | # 149 11: SET { 162 | # 151 9: SEQUENCE { 163 | # 153 3: OBJECT IDENTIFIER countryName (2 5 4 6) 164 | # 158 2: PrintableString 'CH' 165 | # : } 166 | # : } 167 | # 162 43: SET { 168 | # 164 41: SEQUENCE { 169 | # 166 9: OBJECT IDENTIFIER emailAddress (1 2 840 113549 1 9 1) 170 | # 177 28: IA5String 'ascertia@ofcourseimright.com' 171 | # : } 172 | # : } 173 | # 207 19: SET { 174 | # 209 17: SEQUENCE { 175 | # 211 3: OBJECT IDENTIFIER commonName (2 5 4 3) 176 | # 216 10: PrintableString 'Eliot Lear' 177 | # : } 178 | # : } 179 | # : } 180 | #[...] 181 | # 182 | # The representation is generated as follows. 183 | # A SEQUENCE is represented in this configuration in the usr_cert section 184 | # below as "1.3.6.1.5.5.7.1.30=ASN1:SEQ:mud_signers" where "mud_signers" 185 | # refers to the section "mud_signers" 186 | # 187 | # A SET is generated by referring within that section to a "SET", 188 | # for example: countryName=SET:cname_section 189 | # 190 | # This in turn requires another SEQUENCE, which is specified in our 191 | # example in the "cname_section" as cname_seq_type=SEQ:cname_seq 192 | # 193 | # Finally in the cname_seq section we can name the actual OID and country name. 194 | # cname_oid=OID:2.5.4.6 195 | # cname_val=PRINTABLESTRING:"CH" 196 | 197 | 198 | countryName=SET:cname_section 199 | emailAddress=SET:email_section 200 | CN=SET:cn_section 201 | 202 | [ cname_section ] 203 | cname_seq_type=SEQ:cname_seq 204 | 205 | [ cname_seq ] 206 | cname_oid=OID:2.5.4.6 207 | cname_val=PRINTABLESTRING:"US" 208 | 209 | [ email_section ] 210 | email_seq_type=SEQ:email_seq 211 | 212 | [ email_seq ] 213 | emailOID=OID:1.2.840.113549.1.9.1 214 | email_val=IA5:"whatever@happens.com" 215 | 216 | [ cn_section ] 217 | cn_seq_type=SEQ:cn_seq 218 | 219 | [ cn_seq ] 220 | cn_oid=OID:2.5.4.3 221 | cn_val=PRINTABLESTRING:"John Smith" 222 | 223 | [ usr_cert ] 224 | 225 | # These extensions are added when 'ca' signs a request. 226 | 227 | # This goes against PKIX guidelines but some CAs do it and some software 228 | # requires this to avoid interpreting an end user certificate as a CA. 229 | 230 | basicConstraints=CA:FALSE 231 | 232 | # Here are some examples of the usage of nsCertType. If it is omitted 233 | # the certificate can be used for anything *except* object signing. 234 | 235 | # This is OK for an SSL server. 236 | # nsCertType = server 237 | 238 | # For an object signing certificate this would be used. 239 | # nsCertType = objsign 240 | 241 | # For normal client use this is typical 242 | # nsCertType = client, email 243 | 244 | # and for everything including object signing: 245 | # nsCertType = client, email, objsign 246 | 247 | # This is typical in keyUsage for a client certificate. 248 | # keyUsage = nonRepudiation, digitalSignature, keyEncipherment 249 | 250 | # This will be displayed in Netscape's comment listbox. 251 | # nsComment = "OpenSSL Generated Certificate" 252 | 1.3.6.1.5.5.7.1.25=ASN1:IA5STRING:https://www.ofcourseimright.com/Luminaire_150.json 253 | 1.3.6.1.5.5.7.1.30=ASN1:SEQ:mud_signers 254 | -------------------------------------------------------------------------------- /examples/certs_and_keys/openssl-root.cnf: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # The content of this file is taken from the "Guide for building an ECC pki" 3 | # draft available at 4 | # https://datatracker.ietf.org/doc/draft-moskowitz-ecdsa-pki/?include_text=1 5 | ############################################################################## 6 | 7 | # OpenSSL root CA configuration file. 8 | # Copy to `$dir/openssl-root.cnf`. 9 | 10 | [ ca ] 11 | # `man ca` 12 | default_ca = CA_default 13 | 14 | [ CA_default ] 15 | # Directory and file locations. 16 | dir = $ENV::rootca 17 | cadir = $ENV::cadir 18 | format = $ENV::format 19 | 20 | certs = $dir/certs 21 | crl_dir = $dir/crl 22 | new_certs_dir = $dir/newcerts 23 | database = $dir/index.txt 24 | serial = $dir/serial 25 | RANDFILE = $dir/private/.rand 26 | 27 | # The root key and root certificate. 28 | private_key = $dir/private/ca.key.$format 29 | certificate = $cadir/certs/ca.cert.$format 30 | 31 | # For certificate revocation lists. 32 | crlnumber = $dir/crlnumber 33 | crl = $dir/crl/ca.crl.pem 34 | crl_extensions = crl_ext 35 | default_crl_days = 30 36 | 37 | # SHA-1 is deprecated, so use SHA-2 instead. 38 | default_md = sha256 39 | 40 | name_opt = ca_default 41 | cert_opt = ca_default 42 | default_days = 375 43 | preserve = no 44 | policy = policy_strict 45 | copy_extensions = copy 46 | 47 | [ policy_strict ] 48 | # The root CA should only sign intermediate certificates that match. 49 | # See the POLICY FORMAT section of `man ca`. 50 | countryName = optional 51 | stateOrProvinceName = optional 52 | organizationName = optional 53 | organizationalUnitName = optional 54 | commonName = optional 55 | 56 | [ policy_loose ] 57 | # Allow the intermediate CA to sign a more 58 | # diverse range of certificates. 59 | # See the POLICY FORMAT section of the `ca` man page. 60 | countryName = optional 61 | stateOrProvinceName = optional 62 | localityName = optional 63 | organizationName = optional 64 | organizationalUnitName = optional 65 | commonName = optional 66 | 67 | [ req ] 68 | # Options for the `req` tool (`man req`). 69 | default_bits = 2048 70 | distinguished_name = req_distinguished_name 71 | string_mask = utf8only 72 | req_extensions = req_ext 73 | 74 | # SHA-1 is deprecated, so use SHA-2 instead. 75 | default_md = sha256 76 | 77 | # Extension to add when the -x509 option is used. 78 | x509_extensions = v3_ca 79 | 80 | [ req_distinguished_name ] 81 | # See . 82 | countryName = Country Name (2 letter code) 83 | stateOrProvinceName = State or Province Name 84 | localityName = Locality Name 85 | 86 | 0.organizationName = Organization Name 87 | organizationalUnitName = Organizational Unit Name 88 | commonName = Common Name 89 | 90 | # Optionally, specify some defaults. 91 | # countryName_default = US 92 | # stateOrProvinceName_default = MI 93 | # localityName_default = Oak Park 94 | # 0.organizationName_default = HTT Consulting 95 | # organizationalUnitName_default = 96 | 97 | [ req_ext ] 98 | subjectAltName = $ENV::subjectAltName 99 | 100 | [ v3_ca ] 101 | # Extensions for a typical CA (`man x509v3_config`). 102 | subjectKeyIdentifier = hash 103 | authorityKeyIdentifier = keyid:always,issuer 104 | basicConstraints = critical, CA:true 105 | # keyUsage = critical, digitalSignature, cRLSign, keyCertSign 106 | keyUsage = critical, cRLSign, keyCertSign 107 | subjectAltName = $ENV::subjectAltName 108 | 109 | [ v3_intermediate_ca ] 110 | # Extensions for a typical intermediate CA (`man x509v3_config`). 111 | subjectKeyIdentifier = hash 112 | authorityKeyIdentifier = keyid:always,issuer 113 | basicConstraints = critical, CA:true, pathlen:0 114 | # keyUsage = critical, digitalSignature, cRLSign, keyCertSign 115 | keyUsage = critical, cRLSign, keyCertSign 116 | 117 | [ crl_ext ] 118 | # Extension for CRLs (`man x509v3_config`). 119 | authorityKeyIdentifier=keyid:always 120 | 121 | [ ocsp ] 122 | # Extension for OCSP signing certificates (`man ocsp`). 123 | basicConstraints = CA:FALSE 124 | subjectKeyIdentifier = hash 125 | authorityKeyIdentifier = keyid,issuer 126 | keyUsage = critical, digitalSignature 127 | extendedKeyUsage = critical, OCSPSigning -------------------------------------------------------------------------------- /examples/certs_and_keys/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # making the bash files executable 4 | find . -name "*.sh" | xargs chmod +x 5 | 6 | # generating root certificate 7 | ./generate-ca-root.sh 8 | 9 | # generating intermediate certificate 10 | ./generate-ca-8021AR.sh 11 | 12 | # generating FreeRADIUS certificate 13 | ./generate-freeradius-cert.sh 14 | 15 | # generating iDevID certificate 16 | ./generate-iDevID-8021AR.sh 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/luminaire/README.md: -------------------------------------------------------------------------------- 1 | # Example: luminaire 2 | 3 | The files in this directory provide a quick example to show how the MUD 4 | Manager works. They assume that the package has been made and installed. 5 | 6 | You may need three shells: one to start the MUD file server, one start the 7 | MUD manager, and one to run a test command. 8 | 9 | 1. Start a MUD file server. Change to the `fs` directory and start the 10 | script. This can be done on the same host as the MUD Manager, or can be on a 11 | different server. 12 | 13 | **Note**: This is just a test scenario -- the MUD file would 14 | typically be located on a MUD file server provided by the manufacturer of 15 | the device, not the organization using the MUD Manager. 16 | 17 | ```bash 18 | sudo ./start_https_mudserver.sh 19 | ``` 20 | 21 | **Note**: This starts the MUD server on port 443. 22 | 23 | 2. Update /etc/hosts to indicate that "luminaire.example.com" resolves to 24 | an address on the host running the MUD file server. 25 | 26 | ```bash 27 | sudo vi /etc/hosts 28 | ``` 29 | 30 | If the MUD file server is running on the same host as the MUD Manager, 31 | add the following line. 32 | 33 | ``` 34 | 127.0.0.1 luminaire.example.com 35 | ``` 36 | 37 | 3. Place the `luminaire-cacert.pem` file in the location specified by the 38 | configuration file 39 | 40 | ```bash 41 | sudo mkdir /home/mudtester 42 | sudo cp luminaire-cacert.pem /home/mudtester 43 | ``` 44 | 45 | 4. Ensure that the MongoDB collections used by the MUD Manager are empty 46 | 47 | ```bash 48 | mud_clobber_db 49 | ``` 50 | 51 | 5. Start the MUD Manager using the configuration file in this example. 52 | 53 | ```bash 54 | mud_manager -f ./luminaire_conf.json 55 | ``` 56 | 57 | 6. Run the following command 58 | 59 | ```bash 60 | mud_test_client -f Luminaire_150 -c 127.0.0.1 -p 8000 -w luminaire.example.com 61 | ``` 62 | 63 | The output should look similar to the `test_client_output.txt` in this 64 | directory: 65 | 66 | ``` 67 | URL: https://luminaire.example.com/Luminaire_150 68 | 69 | Starting RESTful client against http://127.0.0.1:8000/getaclname 70 | with request { 71 | "MUD_URI": "https://luminaire.example.com/Luminaire_150" 72 | } 73 | Got ACL Names 74 | Full ACL Name 0: ACS:CiscoSecure-Defined-ACL=mud-21966-v4fr.in 75 | ACLname: mud-21966-v4fr.in 76 | 77 | Starting RESTful client against http://127.0.0.1:8000/getaclpolicy with 78 | request { 79 | "ACL_NAME": "mud-21966-v4fr.in" 80 | } 81 | Username: mud-21966-v4fr.in 82 | Got DACL contents: 83 | ACE: ip:inacl#10=permit tcp any host 172.12.212.10 range 443 443 84 | established 85 | ACE: ip:inacl#20=permit udp any host 10.1.1.4 range 5684 5684 86 | ACE: ip:inacl#30=permit udp any host 255.255.255.255 range 5683 5683 87 | ACE: ip:inacl#40=permit udp any any eq 53 88 | ACE: ip:inacl#41=deny ip any any 89 | ``` 90 | 91 | -------------------------------------------------------------------------------- /examples/luminaire/README.txt: -------------------------------------------------------------------------------- 1 | Example: luminaire 2 | 3 | The files in this directory provide a quick example to show how the MUD 4 | Manager works. They assume that the package has been made and installed. 5 | 6 | You may need three shells: one to start the MUD file server, one start the 7 | MUD manager, and one to run a test command. 8 | 9 | (1) Start a MUD file server. Change to the "fs" directory and start the 10 | script. This can be done on the same host as the MUD Manager, or can be on a 11 | different server. Note: This is just a test scenario -- the MUD file would 12 | typically be located on a MUD file server provided by the manufacturer of 13 | the device, not the organization using the MUD Manager. 14 | 15 | sudo ./start_https_mudserver.sh 16 | 17 | Note: This starts the MUD server on port 443. 18 | 19 | (2) Update /etc/hosts to indicate that "luminaire.example.com" resolves to 20 | an address on the host running the MUD file server. 21 | 22 | sudo vi /etc/hosts 23 | 24 | If the MUD file server is running on the same host as the MUD Manager, 25 | add the following line. 26 | 27 | 127.0.0.1 luminaire.example.com 28 | 29 | (3) Place the luminaire-cacert.pem file in the location specified by the 30 | configuration file 31 | 32 | sudo mkdir /home/mudtester 33 | sudo cp luminaire-cacert.pem /home/mudtester 34 | 35 | (4) Ensure that the MongoDB collections used by the MUD Manager are empty 36 | 37 | mud_clobber_db 38 | 39 | (5) Start the MUD Manager using the configuration file in this example. 40 | 41 | mud_manager -f ./luminaire_conf.json 42 | 43 | (6) Run the following command 44 | 45 | mud_test_client -f Luminaire_150 -c 127.0.0.1 -p 8000 \ 46 | -w luminaire.example.com 47 | 48 | The output should look similar to the test_client_output.txt in this directory. 49 | -------------------------------------------------------------------------------- /examples/luminaire/fs/Luminaire_150.json: -------------------------------------------------------------------------------- 1 | { 2 | "ietf-mud:mud": { 3 | "mud-version": 1, 4 | "mud-url": "https://luminaire.example.com/Luminaire_150", 5 | "last-update": "2018-06-29T19:50:19+02:00", 6 | "cache-validity": 48, 7 | "is-supported": true, 8 | "systeminfo": "MUD-enabled Luminaire", 9 | "from-device-policy": { 10 | "access-lists": { 11 | "access-list": [ 12 | { 13 | "name": "mud-21966-v4fr" 14 | } 15 | ] 16 | } 17 | }, 18 | "to-device-policy": { 19 | "access-lists": { 20 | "access-list": [ 21 | { 22 | "name": "mud-21966-v4to" 23 | } 24 | ] 25 | } 26 | } 27 | }, 28 | "ietf-access-control-list:acls": { 29 | "acl": [ 30 | { 31 | "name": "mud-21966-v4to", 32 | "type": "ipv4-acl-type", 33 | "aces": { 34 | "ace": [ 35 | { 36 | "name": "cl0-todev", 37 | "matches": { 38 | "ipv4": { 39 | "ietf-acldns:src-dnsname": "fw-update.luminaire.example.com", 40 | "protocol": 6 41 | }, 42 | "tcp": { 43 | "ietf-mud:direction-initiated": "from-device", 44 | "source-port": { 45 | "operator": "eq", 46 | "port": 443 47 | } 48 | } 49 | }, 50 | "actions": { 51 | "forwarding": "accept" 52 | } 53 | }, 54 | { 55 | "name": "myctl0-todev", 56 | "matches": { 57 | "ietf-mud:mud": { 58 | "my-controller": [ 59 | null 60 | ] 61 | }, 62 | "ipv4": { 63 | "protocol": 17 64 | }, 65 | "udp": { 66 | "source-port": { 67 | "operator": "eq", 68 | "port": 5684 69 | } 70 | } 71 | }, 72 | "actions": { 73 | "forwarding": "accept" 74 | } 75 | }, 76 | { 77 | "name": "loc0-todev", 78 | "matches": { 79 | "ietf-mud:mud": { 80 | "local-networks": [ 81 | null 82 | ] 83 | }, 84 | "ipv4": { 85 | "protocol": 17 86 | }, 87 | "udp": { 88 | "source-port": { 89 | "operator": "eq", 90 | "port": 5683 91 | } 92 | } 93 | }, 94 | "actions": { 95 | "forwarding": "accept" 96 | } 97 | } 98 | ] 99 | } 100 | }, 101 | { 102 | "name": "mud-21966-v4fr", 103 | "type": "ipv4-acl-type", 104 | "aces": { 105 | "ace": [ 106 | { 107 | "name": "cl0-frdev", 108 | "matches": { 109 | "ipv4": { 110 | "ietf-acldns:dst-dnsname": "fw-update.luminaire.example.com", 111 | "protocol": 6 112 | }, 113 | "tcp": { 114 | "ietf-mud:direction-initiated": "from-device", 115 | "destination-port": { 116 | "operator": "eq", 117 | "port": 443 118 | } 119 | } 120 | }, 121 | "actions": { 122 | "forwarding": "accept" 123 | } 124 | }, 125 | { 126 | "name": "myctl0-frdev", 127 | "matches": { 128 | "ietf-mud:mud": { 129 | "my-controller": [ 130 | null 131 | ] 132 | }, 133 | "ipv4": { 134 | "protocol": 17 135 | }, 136 | "udp": { 137 | "destination-port": { 138 | "operator": "eq", 139 | "port": 5684 140 | } 141 | } 142 | }, 143 | "actions": { 144 | "forwarding": "accept" 145 | } 146 | }, 147 | { 148 | "name": "loc0-frdev", 149 | "matches": { 150 | "ietf-mud:mud": { 151 | "local-networks": [ 152 | null 153 | ] 154 | }, 155 | "ipv4": { 156 | "protocol": 17 157 | }, 158 | "udp": { 159 | "destination-port": { 160 | "operator": "eq", 161 | "port": 5683 162 | } 163 | } 164 | }, 165 | "actions": { 166 | "forwarding": "accept" 167 | } 168 | } 169 | ] 170 | } 171 | } 172 | ] 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /examples/luminaire/fs/Luminaire_150.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CiscoDevNet/MUD-Manager/f96502a384b4e10d2c1c862c31080e10b5b00f45/examples/luminaire/fs/Luminaire_150.p7s -------------------------------------------------------------------------------- /examples/luminaire/fs/MUD_FS_HTTPS_cert.pem: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 2 (0x2) 5 | Signature Algorithm: ecdsa-with-SHA256 6 | Issuer: O=Demo Luminaire Manufacturer 7 | Validity 8 | Not Before: Jul 12 20:54:39 2018 GMT 9 | Not After : Jul 9 20:54:39 2028 GMT 10 | Subject: O=Demo Luminaire Manufacturer, CN=luminaire.example.com 11 | Subject Public Key Info: 12 | Public Key Algorithm: id-ecPublicKey 13 | Public-Key: (256 bit) 14 | pub: 15 | 04:dd:b6:a1:df:ac:e4:24:26:b2:21:02:c7:9b:80: 16 | 7c:4e:ed:ba:8a:ae:18:e0:42:32:89:58:d8:88:4b: 17 | 17:7e:65:1d:55:ec:49:99:f3:5d:e3:39:0e:59:8a: 18 | d3:c3:9f:3d:0b:64:32:3d:c8:0a:0d:c7:aa:f2:b5: 19 | 0f:b1:b9:df:74 20 | ASN1 OID: prime256v1 21 | NIST CURVE: P-256 22 | X509v3 extensions: 23 | X509v3 Key Usage: 24 | Digital Signature, Key Encipherment 25 | X509v3 Authority Key Identifier: 26 | keyid:B6:B5:82:ED:65:A9:80:99:44:8E:50:9C:50:DF:48:41:50:FF:BC:35 27 | 28 | Signature Algorithm: ecdsa-with-SHA256 29 | 30:46:02:21:00:92:fa:44:a6:92:98:23:03:30:dc:25:81:b3: 30 | 91:d0:6a:67:12:6d:67:f8:f8:5b:cd:fe:e0:0d:38:53:7b:70: 31 | 21:02:21:00:ad:d0:53:6e:36:10:ac:7a:44:98:f8:e0:5d:20: 32 | 21:0b:7a:b4:13:5d:6f:e4:f0:62:61:f8:f1:05:c5:f0:7c:78 33 | -----BEGIN CERTIFICATE----- 34 | MIIBjDCCATGgAwIBAgIBAjAKBggqhkjOPQQDAjAmMSQwIgYDVQQKDBtEZW1vIEx1 35 | bWluYWlyZSBNYW51ZmFjdHVyZXIwHhcNMTgwNzEyMjA1NDM5WhcNMjgwNzA5MjA1 36 | NDM5WjBGMSQwIgYDVQQKDBtEZW1vIEx1bWluYWlyZSBNYW51ZmFjdHVyZXIxHjAc 37 | BgNVBAMMFWx1bWluYWlyZS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49 38 | AwEHA0IABN22od+s5CQmsiECx5uAfE7tuoquGOBCMolY2IhLF35lHVXsSZnzXeM5 39 | DlmK08OfPQtkMj3ICg3HqvK1D7G533SjMDAuMAsGA1UdDwQEAwIFoDAfBgNVHSME 40 | GDAWgBS2tYLtZamAmUSOUJxQ30hBUP+8NTAKBggqhkjOPQQDAgNJADBGAiEAkvpE 41 | ppKYIwMw3CWBs5HQamcSbWf4+FvN/uANOFN7cCECIQCt0FNuNhCsekSY+OBdICEL 42 | erQTXW/k8GJh+PEFxfB8eA== 43 | -----END CERTIFICATE----- 44 | -------------------------------------------------------------------------------- /examples/luminaire/fs/MUD_FS_HTTPS_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BggqhkjOPQMBBw== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MHcCAQEEIMjjg7U5aXz3Jvw/9XDk/VXkvsUuCRGZNzBiKmPSjMt+oAoGCCqGSM49 6 | AwEHoUQDQgAE3bah36zkJCayIQLHm4B8Tu26iq4Y4EIyiVjYiEsXfmUdVexJmfNd 7 | 4zkOWYrTw589C2QyPcgKDceq8rUPsbnfdA== 8 | -----END EC PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /examples/luminaire/fs/mud_https_server.py: -------------------------------------------------------------------------------- 1 | import http.server 2 | from http import HTTPStatus 3 | import socketserver 4 | import ssl 5 | import sys, getopt 6 | import os 7 | 8 | class Server(http.server.SimpleHTTPRequestHandler): 9 | def do_GET(self): 10 | 11 | request = self.path[1:] # strip off leading / 12 | basename = os.path.basename(request) 13 | ext = os.path.splitext(basename) 14 | 15 | #print(self.headers) 16 | print("ServerRequest: {0}".format(request)) 17 | 18 | is_signed = ext[1] == ".p7s" 19 | 20 | try: 21 | fp = open(request, "rb") 22 | except: 23 | self.send_error(404) 24 | print("Unable to open file {0}".format(request)) 25 | else: 26 | stuff = fp.read() 27 | if not is_signed: 28 | print(stuff) 29 | 30 | try: 31 | self.send_response(HTTPStatus.OK) 32 | if is_signed: 33 | self.send_header("Content-Type", "application/pkcs7-signature") 34 | else: 35 | self.send_header("Content-Type", "application/mud+json") 36 | self.end_headers() 37 | self.wfile.write(stuff) 38 | print("Response is sent") 39 | except: 40 | print("Error in writing respone") 41 | 42 | print("done") 43 | return 44 | 45 | 46 | def main(argv): 47 | certfile = '' 48 | keyfile = '' 49 | port = 443 50 | try: 51 | opts, args = getopt.getopt(argv,"c:k:p:") 52 | except getopt.GetoptError: 53 | print('mud_https_server.py -c -k [-p ]') 54 | for opt,arg in opts: 55 | if opt == '-c': 56 | certfile = arg 57 | elif opt == '-k': 58 | keyfile = arg 59 | elif opt == '-p': 60 | port = int(arg) 61 | print('Certfile is:', certfile) 62 | print('Keyfile is:', keyfile) 63 | 64 | httpd = http.server.HTTPServer(('', port), Server) 65 | print("Starting HTTP Server") 66 | httpd.socket = ssl.wrap_socket(httpd.socket, keyfile=keyfile, certfile=certfile, server_side=True) 67 | httpd.serve_forever() 68 | 69 | if __name__ == "__main__": 70 | main(sys.argv[1:]) 71 | 72 | 73 | -------------------------------------------------------------------------------- /examples/luminaire/fs/start_https_mudserver.sh: -------------------------------------------------------------------------------- 1 | CERT=./MUD_FS_HTTPS_cert.pem 2 | KEY=./MUD_FS_HTTPS_key.pem 3 | 4 | python3 mud_https_server.py -c $CERT -k $KEY -p 443 5 | 6 | -------------------------------------------------------------------------------- /examples/luminaire/luminaire-cacert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIBlDCCATmgAwIBAgIJAIhsLVzaDjNzMAoGCCqGSM49BAMCMCYxJDAiBgNVBAoM 3 | G0RlbW8gTHVtaW5haXJlIE1hbnVmYWN0dXJlcjAeFw0xODA3MTIyMDU0MzVaFw0x 4 | OTA3MTIyMDU0MzVaMCYxJDAiBgNVBAoMG0RlbW8gTHVtaW5haXJlIE1hbnVmYWN0 5 | dXJlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDuVWN7KgCRoqiGu8pS4jbqD 6 | hfSctrX48SgxWezD3PDGd8arVpvsG95C5L9LvK6q+seSLnY5BDHf4EcAvGcT6+Kj 7 | UDBOMB0GA1UdDgQWBBS2tYLtZamAmUSOUJxQ30hBUP+8NTAfBgNVHSMEGDAWgBS2 8 | tYLtZamAmUSOUJxQ30hBUP+8NTAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kA 9 | MEYCIQC1rPUPL66grkrMpTpWc71ueWlRwB+In07mShEsZZoZSgIhAKrBoYIyWGgx 10 | HIGEjHutoHCYlWpymX7YujXjx8Spv3Lb 11 | -----END CERTIFICATE----- 12 | -------------------------------------------------------------------------------- /examples/luminaire/luminaire_conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "MUD_Manager_Version" : 2, 3 | "MUDManagerAPIProtocol" : "http", 4 | "ACL_Prefix" : "ACS:", 5 | "ACL_Type" : "dACL-ingress-only", 6 | "COA_Password" : "mudtester", 7 | "Default_Localv4": "10.0.0.0 0.255.255.255", 8 | "Default_VLAN" : 2, 9 | "VLANs" : [ 10 | { 11 | "VLAN_ID" : 5, 12 | "v4addrmask": "10.1.2.0 0.0.0.255" 13 | } 14 | ], 15 | "Manufacturers" : [ 16 | { "authority" : "luminaire.example.com", 17 | "cert": "/home/mudtester/luminaire-cacert.pem", 18 | "my_controller_v4" : "10.1.1.4", 19 | "local_networks_v4" : "10.1.1.0 0.0.0.255" 20 | } 21 | ], 22 | "DNSMapping" : { 23 | "fw-update.luminaire.example.com" : "172.12.212.10" 24 | }, 25 | "ControllerMapping" : { 26 | "http://lightcontroller.example.com" : "10.1.1.5" 27 | }, 28 | "DefaultACL" : ["permit udp any any eq 53", "deny ip any any"] 29 | } 30 | -------------------------------------------------------------------------------- /examples/luminaire/test_client_output.txt: -------------------------------------------------------------------------------- 1 | URL: https://luminaire.example.com/Luminaire_150 2 | 3 | Starting RESTful client against http://127.0.0.1:8000/getaclname 4 | with request { 5 | "MUD_URI": "https://luminaire.example.com/Luminaire_150" 6 | } 7 | Got ACL Names 8 | Full ACL Name 0: ACS:CiscoSecure-Defined-ACL=mud-21966-v4fr.in 9 | ACLname: mud-21966-v4fr.in 10 | 11 | Starting RESTful client against http://127.0.0.1:8000/getaclpolicy with 12 | request { 13 | "ACL_NAME": "mud-21966-v4fr.in" 14 | } 15 | Username: mud-21966-v4fr.in 16 | Got DACL contents: 17 | ACE: ip:inacl#10=permit tcp any host 172.12.212.10 range 443 443 18 | established 19 | ACE: ip:inacl#20=permit udp any host 10.1.1.4 range 5684 5684 20 | ACE: ip:inacl#30=permit udp any host 255.255.255.255 range 5683 5683 21 | ACE: ip:inacl#40=permit udp any any eq 53 22 | ACE: ip:inacl#41=deny ip any any 23 | -------------------------------------------------------------------------------- /examples/mud_manager_conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "MUD_Manager_Version" : 2, 3 | "MUDManagerAPIProtocol" : "http", 4 | "ACL_Prefix" : "ACS:", 5 | "ACL_Type" : "dACL-ingress-only", 6 | "COA_Password" : "mudtester", 7 | "Default_Localv4" : "10.0.0.0 0.255.255.255", 8 | "Default_VLAN": 5, 9 | "VLANs" : [ 10 | { "VLAN_ID" : 18, 11 | "v4addrmask" : "192.168.8.0 0.0.0.255" 12 | }, 13 | { 14 | "VLAN_ID": 4, 15 | "v4addrmask": "10.8.2.0 0.0.0.255" 16 | } 17 | ], 18 | "Manufacturers" : [ 19 | { "authority" : "luminaire.example.com", 20 | "url" : "https://luminaire.example.com/Luminaire_150.json", 21 | "cert": "/home/mudtester/luminaire-cacert.pem", 22 | "my_controller_v4" : "10.1.1.4", 23 | "local_networks_v4" : "10.0.0.0 0.0.0.255" 24 | } 25 | ], 26 | "DNSMapping" : { 27 | "fw-update.luminaire.example.com" : "172.12.212.10" 28 | }, 29 | "DNSMapping_v6" : { 30 | "fw-update.luminaire.example.com" : "1111:2222:4533:2223:::" 31 | }, 32 | "ControllerMapping" : { 33 | "http://lightcontroller.example.com" : "10.1.1.5" 34 | }, 35 | "ControllerMapping_v6" : { 36 | "http://lightcontroller.example.com" : "ffff:2343:4444:::" 37 | }, 38 | "DefaultACL" : ["permit udp any any eq 53", "deny ip any any"], 39 | "DefaultACL_v6" : ["permit udp any any eq 53", "deny ipv6 any any"] 40 | } 41 | -------------------------------------------------------------------------------- /m4/ltsugar.m4: -------------------------------------------------------------------------------- 1 | # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software 4 | # Foundation, Inc. 5 | # Written by Gary V. Vaughan, 2004 6 | # 7 | # This file is free software; the Free Software Foundation gives 8 | # unlimited permission to copy and/or distribute it, with or without 9 | # modifications, as long as this notice is preserved. 10 | 11 | # serial 6 ltsugar.m4 12 | 13 | # This is to help aclocal find these macros, as it can't see m4_define. 14 | AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) 15 | 16 | 17 | # lt_join(SEP, ARG1, [ARG2...]) 18 | # ----------------------------- 19 | # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their 20 | # associated separator. 21 | # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier 22 | # versions in m4sugar had bugs. 23 | m4_define([lt_join], 24 | [m4_if([$#], [1], [], 25 | [$#], [2], [[$2]], 26 | [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) 27 | m4_define([_lt_join], 28 | [m4_if([$#$2], [2], [], 29 | [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) 30 | 31 | 32 | # lt_car(LIST) 33 | # lt_cdr(LIST) 34 | # ------------ 35 | # Manipulate m4 lists. 36 | # These macros are necessary as long as will still need to support 37 | # Autoconf-2.59, which quotes differently. 38 | m4_define([lt_car], [[$1]]) 39 | m4_define([lt_cdr], 40 | [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], 41 | [$#], 1, [], 42 | [m4_dquote(m4_shift($@))])]) 43 | m4_define([lt_unquote], $1) 44 | 45 | 46 | # lt_append(MACRO-NAME, STRING, [SEPARATOR]) 47 | # ------------------------------------------ 48 | # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. 49 | # Note that neither SEPARATOR nor STRING are expanded; they are appended 50 | # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). 51 | # No SEPARATOR is output if MACRO-NAME was previously undefined (different 52 | # than defined and empty). 53 | # 54 | # This macro is needed until we can rely on Autoconf 2.62, since earlier 55 | # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. 56 | m4_define([lt_append], 57 | [m4_define([$1], 58 | m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) 59 | 60 | 61 | 62 | # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) 63 | # ---------------------------------------------------------- 64 | # Produce a SEP delimited list of all paired combinations of elements of 65 | # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list 66 | # has the form PREFIXmINFIXSUFFIXn. 67 | # Needed until we can rely on m4_combine added in Autoconf 2.62. 68 | m4_define([lt_combine], 69 | [m4_if(m4_eval([$# > 3]), [1], 70 | [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl 71 | [[m4_foreach([_Lt_prefix], [$2], 72 | [m4_foreach([_Lt_suffix], 73 | ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, 74 | [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) 75 | 76 | 77 | # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) 78 | # ----------------------------------------------------------------------- 79 | # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited 80 | # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. 81 | m4_define([lt_if_append_uniq], 82 | [m4_ifdef([$1], 83 | [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], 84 | [lt_append([$1], [$2], [$3])$4], 85 | [$5])], 86 | [lt_append([$1], [$2], [$3])$4])]) 87 | 88 | 89 | # lt_dict_add(DICT, KEY, VALUE) 90 | # ----------------------------- 91 | m4_define([lt_dict_add], 92 | [m4_define([$1($2)], [$3])]) 93 | 94 | 95 | # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) 96 | # -------------------------------------------- 97 | m4_define([lt_dict_add_subkey], 98 | [m4_define([$1($2:$3)], [$4])]) 99 | 100 | 101 | # lt_dict_fetch(DICT, KEY, [SUBKEY]) 102 | # ---------------------------------- 103 | m4_define([lt_dict_fetch], 104 | [m4_ifval([$3], 105 | m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), 106 | m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) 107 | 108 | 109 | # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) 110 | # ----------------------------------------------------------------- 111 | m4_define([lt_if_dict_fetch], 112 | [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], 113 | [$5], 114 | [$6])]) 115 | 116 | 117 | # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) 118 | # -------------------------------------------------------------- 119 | m4_define([lt_dict_filter], 120 | [m4_if([$5], [], [], 121 | [lt_join(m4_quote(m4_default([$4], [[, ]])), 122 | lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), 123 | [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl 124 | ]) 125 | -------------------------------------------------------------------------------- /m4/ltversion.m4: -------------------------------------------------------------------------------- 1 | # ltversion.m4 -- version numbers -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # @configure_input@ 11 | 12 | # serial 4179 ltversion.m4 13 | # This file is part of GNU Libtool 14 | 15 | m4_define([LT_PACKAGE_VERSION], [2.4.6]) 16 | m4_define([LT_PACKAGE_REVISION], [2.4.6]) 17 | 18 | AC_DEFUN([LTVERSION_VERSION], 19 | [macro_version='2.4.6' 20 | macro_revision='2.4.6' 21 | _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) 22 | _LT_DECL(, macro_revision, 0) 23 | ]) 24 | -------------------------------------------------------------------------------- /m4/lt~obsolete.m4: -------------------------------------------------------------------------------- 1 | # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software 4 | # Foundation, Inc. 5 | # Written by Scott James Remnant, 2004. 6 | # 7 | # This file is free software; the Free Software Foundation gives 8 | # unlimited permission to copy and/or distribute it, with or without 9 | # modifications, as long as this notice is preserved. 10 | 11 | # serial 5 lt~obsolete.m4 12 | 13 | # These exist entirely to fool aclocal when bootstrapping libtool. 14 | # 15 | # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), 16 | # which have later been changed to m4_define as they aren't part of the 17 | # exported API, or moved to Autoconf or Automake where they belong. 18 | # 19 | # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN 20 | # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us 21 | # using a macro with the same name in our local m4/libtool.m4 it'll 22 | # pull the old libtool.m4 in (it doesn't see our shiny new m4_define 23 | # and doesn't know about Autoconf macros at all.) 24 | # 25 | # So we provide this file, which has a silly filename so it's always 26 | # included after everything else. This provides aclocal with the 27 | # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything 28 | # because those macros already exist, or will be overwritten later. 29 | # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 30 | # 31 | # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. 32 | # Yes, that means every name once taken will need to remain here until 33 | # we give up compatibility with versions before 1.7, at which point 34 | # we need to keep only those names which we still refer to. 35 | 36 | # This is to help aclocal find these macros, as it can't see m4_define. 37 | AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) 38 | 39 | m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) 40 | m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) 41 | m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) 42 | m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) 43 | m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) 44 | m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) 45 | m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) 46 | m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) 47 | m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) 48 | m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) 49 | m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) 50 | m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) 51 | m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) 52 | m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) 53 | m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) 54 | m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) 55 | m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) 56 | m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) 57 | m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) 58 | m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) 59 | m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) 60 | m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) 61 | m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) 62 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) 63 | m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) 64 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) 65 | m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) 66 | m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) 67 | m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) 68 | m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) 69 | m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) 70 | m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) 71 | m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) 72 | m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) 73 | m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) 74 | m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) 75 | m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) 76 | m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) 77 | m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) 78 | m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) 79 | m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) 80 | m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) 81 | m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) 82 | m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) 83 | m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) 84 | m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) 85 | m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) 86 | m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) 87 | m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) 88 | m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) 89 | m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) 90 | m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) 91 | m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) 92 | m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) 93 | m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) 94 | m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) 95 | m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) 96 | m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) 97 | m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) 98 | m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) 99 | m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) 100 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | AM_CFLAGS=-I$(top_srcdir) $(M_CPPFLAGS) -DMG_ENABLE_SSL -Wall -W $(MONGOC_CFLAGS) -Icivetweb -I$(includedir)/cjson 3 | LDADD= $(MONGOC_LIBS) 4 | 5 | 6 | 7 | bin_PROGRAMS = mud_manager mud_test_client 8 | 9 | mud_manager_SOURCES = mud_manager.c log.c sessions.c acl_types.c \ 10 | cisco_dacl.c mud_fs_client.c mud_manager.h \ 11 | config.h sessions.h mud_fs_client.h acl.h \ 12 | acl_types.h log.h cisco_dacl.h \ 13 | civetweb/civetweb.c civetweb/civetweb.h 14 | 15 | 16 | mud_test_client_SOURCES = mud_test_client.c 17 | 18 | -------------------------------------------------------------------------------- /src/acl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | 6 | struct _match { 7 | char* dnsname; /* domain name to match against */ 8 | char *addrmask; /* ip address to match against */ 9 | int protocol; /* protocol to match against */ 10 | int is_ipv6; /* are we IPv6 */ 11 | int src_lower_port; 12 | int src_upper_port; 13 | int dst_lower_port; 14 | int dst_upper_port; 15 | int dir_initiated; 16 | }; 17 | 18 | typedef struct _ace { 19 | char* rule_name; 20 | struct _match matches; 21 | int action; 22 | int num_ace; 23 | } ACE; 24 | 25 | typedef struct _acl_struct { 26 | char* acl_name; 27 | char* acl_type; 28 | int pak_direction; 29 | ACE *ace; 30 | int ace_count; 31 | int matched; 32 | } ACL; 33 | 34 | /* 35 | * These definitions are used in ACL pak_direction. 36 | */ 37 | #define INGRESS 0 38 | #define EGRESS 1 39 | 40 | /* 41 | * These definitions are used to determine the direction that 42 | * ACLs will be applied to enforce policy. 43 | */ 44 | enum acl_direction { 45 | INGRESS_ONLY_ACL, 46 | INGRESS_EGRESS_ACLS 47 | }; 48 | -------------------------------------------------------------------------------- /src/acl_types.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | * 5 | * Handle different formats for ACL types. 6 | */ 7 | #include 8 | #include "acl.h" 9 | #include "log.h" 10 | #include "acl_types.h" 11 | #include "cisco_dacl.h" 12 | 13 | cJSON* create_policy_from_acllist(enum acl_policy_type acl_type, 14 | ACL *acllist, int acl_count, 15 | enum acl_direction direction, int acl) 16 | { 17 | switch (acl_type) { 18 | case CISCO_DACL: 19 | return create_cisco_dacl_policy(acllist, acl_count, 20 | direction, acl); 21 | default: 22 | MUDC_LOG_ERR("Unsupported ACL type: %d\n", 23 | acl_type); 24 | return NULL; 25 | } 26 | } 27 | 28 | cJSON* get_policy_by_aclname(enum acl_policy_type acl_type, char* acl_name) 29 | { 30 | switch (acl_type) { 31 | case CISCO_DACL: 32 | return get_cisco_dacl_policy(acl_name); 33 | default: 34 | MUDC_LOG_ERR("Unsupported ACL type: %d\n", 35 | acl_type); 36 | return NULL; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/acl_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | 6 | enum acl_policy_type { 7 | CISCO_DACL, 8 | }; 9 | 10 | cJSON* create_policy_from_acllist(enum acl_policy_type response_type, 11 | ACL *acllist, int acl_count, 12 | enum acl_direction direction, int vlan); 13 | 14 | cJSON* get_policy_by_aclname(enum acl_policy_type acl_type, char* acl_name); 15 | 16 | 17 | /* 18 | * Definitions used by code manipulating ACLs in the JSON file. 19 | */ 20 | #define GETSTR_JSONOBJ(j,v) cJSON_GetObjectItem(j,v) ? cJSON_GetObjectItem(j, v)->valuestring: NULL 21 | #define GETSTR_JSONARRAY(j,i) cJSON_GetArrayItem(j, i)->valuestring 22 | #define GETINT_JSONOBJ(j,v) cJSON_GetObjectItem(j,v) ? cJSON_GetObjectItem(j, v)->valueint: 0 23 | 24 | -------------------------------------------------------------------------------- /src/cisco_dacl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | * 5 | * Create a Cisco DACL response for a RADIUS server. 6 | */ 7 | #include 8 | #pragma GCC diagnostic push // suppress specific warning from 3rd-party code 9 | #pragma GCC diagnostic ignored "-Wexpansion-to-defined" 10 | #include 11 | #pragma GCC diagnostic pop 12 | #include "acl.h" 13 | #include "log.h" 14 | #include "acl_types.h" 15 | #include "cisco_dacl.h" 16 | 17 | extern mongoc_collection_t *policies_collection; 18 | 19 | #define MAX_POLICY_NAME_LEN 100 20 | 21 | /* 22 | * Return Cisco DACL RADIUS attributes. 23 | */ 24 | cJSON* create_cisco_dacl_policy(ACL *acllist, int acl_count, 25 | enum acl_direction direction, int use_vlan) 26 | { 27 | cJSON *response_acl=NULL, *parsed_json=NULL, *acefmt=NULL; 28 | char *ace_ptr=NULL, *acl_prefix=NULL; 29 | char policy_name[MAX_POLICY_NAME_LEN], ace_str[1024]; 30 | int ace_index=0, index=0, i=0; 31 | char *txt=NULL; 32 | char *dnsname=NULL; 33 | char *addrmask=NULL; 34 | char *aceaction=NULL; 35 | 36 | 37 | if (acllist == NULL || acl_count <= 0) { 38 | MUDC_LOG_ERR("Invalid parameters"); 39 | return NULL; 40 | } 41 | 42 | memset(policy_name, 0, MAX_POLICY_NAME_LEN); 43 | parsed_json = cJSON_CreateArray(); 44 | ace_ptr = ace_str; 45 | 46 | /* 47 | * Build dACLs for each ACL in the list. 48 | */ 49 | for (index=0; index < acl_count; index++) { 50 | if ((acllist[index].pak_direction == EGRESS) && 51 | (direction == INGRESS_ONLY_ACL)) { 52 | MUDC_LOG_INFO("Building INGRESS ACLs only"); 53 | continue; 54 | } 55 | 56 | response_acl = cJSON_CreateObject(); 57 | if (response_acl == NULL) { 58 | MUDC_LOG_ERR("Error allocating response_acl"); 59 | cJSON_Delete(parsed_json); 60 | return NULL; 61 | } 62 | 63 | MUDC_LOG_INFO("ACLName <%s> %d", acllist[index].acl_name, 64 | acllist[index].pak_direction); 65 | if (acl_list_prefix != NULL) { 66 | sprintf(policy_name, "%s", acl_list_prefix); 67 | } 68 | /* 69 | * The name is currently taken directly from the MUD file, which 70 | * isn't guaranteed to be unique. Two MUD files could choose the same 71 | * name. So when we create the DACL name, we should add a counter or 72 | * random value to the name that would premute the name a bit. 73 | * E.g., instead of 74 | * mud-85729-v6fr.in 75 | * make it 76 | * mm10430-mud-85729-v6fr.in 77 | * where "mm" is leading tag, and "10430" comes from a RNG each time 78 | * that policies are generated from a MUD URL and stored in mongodb. 79 | */ 80 | if (acllist[index].pak_direction == INGRESS) { 81 | sprintf(policy_name, "%sCiscoSecure-Defined-ACL=%s.in", 82 | policy_name, acllist[index].acl_name); 83 | acl_prefix="inacl"; 84 | } else if (acllist[index].pak_direction == EGRESS) { 85 | sprintf(policy_name, "%sCiscoSecure-Defined-ACL=%s.out", 86 | policy_name, acllist[index].acl_name); 87 | acl_prefix="outacl"; 88 | } 89 | 90 | cJSON_AddItemToObject(response_acl, "DACL_Name", 91 | cJSON_CreateString(policy_name)); 92 | cJSON_AddItemToObject(response_acl, "DACL", 93 | acefmt = cJSON_CreateArray()); 94 | if (use_vlan > 0) 95 | cJSON_AddItemToObject(response_acl, "VLAN", cJSON_CreateNumber(use_vlan)); 96 | MUDC_LOG_INFO("Ace Count <%d>", acllist[index].ace_count); 97 | for (ace_index=0; ace_index < acllist[index].ace_count; ace_index++) { 98 | if (strcmp(acllist[index].acl_type, "ipv4") == 0) { 99 | ace_ptr+= sprintf(ace_ptr, "ip:"); 100 | } else if (strcmp(acllist[index].acl_type, "ipv6") == 0) { 101 | ace_ptr+= sprintf(ace_ptr, "ipv6:"); 102 | } 103 | 104 | if (acllist[index].ace[ace_index].action == 1) 105 | aceaction=ACEPERMIT; 106 | else 107 | aceaction=ACEDENY; 108 | if (acllist[index].ace[ace_index].num_ace == 2) { 109 | ace_ptr+= sprintf(ace_ptr, aceaction, acl_prefix, 110 | (ace_index+1)*10-1); 111 | } else { 112 | ace_ptr+= sprintf(ace_ptr, aceaction, acl_prefix, 113 | (ace_index+1)*10); 114 | } 115 | 116 | if (acllist[index].ace[ace_index].matches.protocol == 6) { 117 | ace_ptr+= sprintf(ace_ptr, " tcp"); 118 | } else if (acllist[index].ace[ace_index].matches.protocol == 17) { 119 | ace_ptr+= sprintf(ace_ptr, " udp"); 120 | } else { 121 | ace_ptr+= sprintf(ace_ptr," ip"); 122 | } 123 | 124 | if (acllist[index].pak_direction == INGRESS) { 125 | ace_ptr += sprintf(ace_ptr, " any"); 126 | if ((acllist[index].ace[ace_index].matches.src_lower_port != 0) 127 | && (acllist[index].ace[ace_index].matches.src_upper_port 128 | != 0 )) { 129 | ace_ptr += sprintf(ace_ptr, " range %d %d", 130 | acllist[index].ace[ace_index].matches.src_lower_port, 131 | acllist[index].ace[ace_index].matches.src_upper_port); 132 | } 133 | } 134 | 135 | if ( (dnsname = acllist[index].ace[ace_index].matches.dnsname) ) { 136 | if (strcmp(dnsname, "any") == 0) { 137 | ace_ptr += sprintf(ace_ptr, " any"); 138 | } else { 139 | ace_ptr += sprintf(ace_ptr, " host %s", dnsname); 140 | } 141 | } else if ( (addrmask = acllist[index].ace[ace_index].matches.addrmask) ) { /* it can either be a name or an 142 | * address mask 143 | */ 144 | ace_ptr += sprintf(ace_ptr," %s", addrmask); 145 | } 146 | 147 | 148 | 149 | 150 | 151 | if (acllist[index].pak_direction == INGRESS) { 152 | if ((acllist[index].ace[ace_index].matches.dst_lower_port != 0) 153 | && (acllist[index].ace[ace_index].matches.dst_upper_port 154 | != 0 )) { 155 | ace_ptr += sprintf(ace_ptr, " range %d %d", 156 | acllist[index].ace[ace_index].matches.dst_lower_port, 157 | acllist[index].ace[ace_index].matches.dst_upper_port); 158 | } 159 | } else if (acllist[index].pak_direction == EGRESS) { 160 | if ((acllist[index].ace[ace_index].matches.src_lower_port != 0) 161 | && (acllist[index].ace[ace_index].matches.src_upper_port 162 | != 0 )) { 163 | ace_ptr += sprintf(ace_ptr, " range %d %d", 164 | acllist[index].ace[ace_index].matches.src_lower_port, 165 | acllist[index].ace[ace_index].matches.src_upper_port); 166 | } 167 | ace_ptr += sprintf(ace_ptr, " any"); 168 | if ((acllist[index].ace[ace_index].matches.dst_lower_port != 0) 169 | && (acllist[index].ace[ace_index].matches.dst_upper_port 170 | != 0 )) { 171 | ace_ptr += sprintf(ace_ptr, " range %d %d", 172 | acllist[index].ace[ace_index].matches.dst_lower_port, 173 | acllist[index].ace[ace_index].matches.dst_upper_port); 174 | } 175 | } 176 | 177 | if ((acllist[index].ace[ace_index].matches.protocol == 6) && 178 | (acllist[index].ace[ace_index].matches.dir_initiated != -1)) { 179 | if (acllist[index].ace[ace_index].num_ace == 2) { 180 | ace_ptr += sprintf(ace_ptr, " syn"); 181 | acllist[index].ace[ace_index].num_ace--; 182 | ace_index--; 183 | } else { 184 | /* do not ever apply ESTABLISHED on ingress ACLs */ 185 | if (acllist[index].pak_direction == INGRESS) { 186 | if (direction == INGRESS_ONLY_ACL) 187 | ace_ptr += sprintf(ace_ptr, " syn ack"); /* if we are doing ingress only 188 | * ACLs the best we can do is block 189 | * on syn acks on ingress. 190 | */ 191 | 192 | } else 193 | ace_ptr += sprintf(ace_ptr, " established"); 194 | } 195 | } 196 | MUDC_LOG_INFO("ACE Ptr: %s", ace_str); 197 | cJSON_AddItemToArray(acefmt, cJSON_CreateString(ace_str)); 198 | ace_ptr = ace_str; 199 | } 200 | 201 | /* 202 | * Find any ACL definitions to add. If not, add "deny ip any any". 203 | */ 204 | 205 | if (strcmp(acllist[index].acl_type, "ipv4") == 0) { 206 | if (defacl_json == NULL) { 207 | MUDC_LOG_INFO("Using hardcoded default IPv4 ACL"); 208 | ace_ptr += sprintf(ace_ptr, "ip:%s#%d=deny ip any any", 209 | acl_prefix, (ace_index+1)*10); 210 | cJSON_AddItemToArray(acefmt, cJSON_CreateString(ace_str)); 211 | ace_ptr = ace_str; 212 | } else { 213 | for (i=0; i < cJSON_GetArraySize(defacl_json); i++) { 214 | ace_ptr += sprintf(ace_ptr, "ip:%s#%d=%s", acl_prefix, 215 | (ace_index+1)*10+i, 216 | GETSTR_JSONARRAY(defacl_json, i)); 217 | cJSON_AddItemToArray(acefmt, cJSON_CreateString(ace_str)); 218 | ace_ptr = ace_str; 219 | } 220 | } 221 | } else { /* ipv6 */ 222 | if (defacl_v6_json == NULL) { 223 | MUDC_LOG_INFO("Using hardcoded default IPv6 ACL"); 224 | ace_ptr += sprintf(ace_ptr, "ipv6:%s#%d=deny ipv6 any any", 225 | acl_prefix, (ace_index+1)*10); 226 | cJSON_AddItemToArray(acefmt, cJSON_CreateString(ace_str)); 227 | ace_ptr = ace_str; 228 | } else { 229 | for (i=0; i < cJSON_GetArraySize(defacl_v6_json); i++) { 230 | ace_ptr += sprintf(ace_ptr, "ipv6:%s#%d=%s", acl_prefix, 231 | (ace_index+1)*10+i, 232 | GETSTR_JSONARRAY(defacl_v6_json, i)); 233 | cJSON_AddItemToArray(acefmt, cJSON_CreateString(ace_str)); 234 | ace_ptr = ace_str; 235 | } 236 | } 237 | } 238 | 239 | cJSON_AddItemToArray(parsed_json, cJSON_Duplicate(response_acl, 240 | (cJSON_bool)1)); 241 | 242 | cJSON_Delete(response_acl); 243 | } 244 | 245 | txt = cJSON_Print(parsed_json); 246 | if (txt != NULL) { 247 | MUDC_LOG_INFO("Returning parsed_json %s", txt); 248 | free(txt); 249 | } 250 | return(parsed_json); 251 | } 252 | 253 | cJSON* get_cisco_dacl_policy(char *acl_name) 254 | { 255 | char policy_name[MAX_POLICY_NAME_LEN]; 256 | bson_t *filter=NULL; 257 | const bson_t *record=NULL; 258 | mongoc_cursor_t *cursor=NULL; 259 | char *found_str=NULL, *dacl_str = NULL; 260 | cJSON *jsonResponse=NULL; 261 | cJSON *dacl_list; 262 | cJSON *json=NULL, *dacl=NULL; 263 | int index=0; 264 | 265 | memset(policy_name, 0, MAX_POLICY_NAME_LEN); 266 | sprintf(policy_name, "%sCiscoSecure-Defined-ACL=%s", 267 | acl_list_prefix, acl_name); 268 | MUDC_LOG_INFO("ACL Name <%s>\n", acl_name); 269 | 270 | filter = BCON_NEW("DACL_Name", BCON_UTF8(policy_name)); 271 | cursor = mongoc_collection_find_with_opts(policies_collection, 272 | filter, NULL, NULL); 273 | 274 | jsonResponse = cJSON_CreateObject(); 275 | cJSON_AddItemToObject(jsonResponse, "User-Name", 276 | cJSON_CreateString(acl_name)); 277 | cJSON_AddItemToObject(jsonResponse, "Cisco-AVPair", 278 | dacl_list = cJSON_CreateArray()); 279 | 280 | MUDC_LOG_INFO("Create Array \n"); 281 | while (mongoc_cursor_next(cursor, &record)) { 282 | found_str = bson_as_json(record, NULL); 283 | if (found_str!=NULL) { 284 | MUDC_LOG_INFO("found the record <%s>\n", found_str); 285 | json = cJSON_Parse(found_str); 286 | if (!json) { 287 | MUDC_LOG_ERR("Error Before: [%s]\n", cJSON_GetErrorPtr()); 288 | } else { 289 | int size = 0; 290 | dacl_str = GETSTR_JSONOBJ(json,"DACL"); 291 | dacl = cJSON_Parse(dacl_str); 292 | size = cJSON_GetArraySize(dacl); 293 | for (index=0;index < size; index++) { 294 | cJSON_AddItemToArray(dacl_list, 295 | cJSON_Duplicate(cJSON_GetArrayItem(dacl,index), 296 | true)); 297 | } 298 | cJSON_Delete(json); 299 | cJSON_Delete(dacl); 300 | } 301 | bson_free(found_str); 302 | } 303 | } 304 | 305 | if (cJSON_GetArraySize(dacl_list) <= 0) { 306 | MUDC_LOG_ERR("No DACLs found."); 307 | /* Deleting jsonResponse also frees memory for dacl_list */ 308 | cJSON_Delete(jsonResponse); 309 | jsonResponse = NULL; 310 | } 311 | 312 | mongoc_cursor_destroy(cursor); 313 | bson_destroy(filter); 314 | 315 | return jsonResponse; 316 | } 317 | 318 | -------------------------------------------------------------------------------- /src/cisco_dacl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | 6 | extern char *acl_list_prefix; 7 | extern cJSON *defacl_json; 8 | extern cJSON *defacl_v6_json; 9 | 10 | static char *ACEPERMIT="%s#%d=permit"; 11 | static char *ACEDENY="%s#%d=deny"; 12 | 13 | cJSON* create_cisco_dacl_policy(ACL *acllist, int acl_count, 14 | enum acl_direction direction, int use_vlan); 15 | 16 | cJSON* get_cisco_dacl_policy(char *acl_name); 17 | 18 | -------------------------------------------------------------------------------- /src/civetweb/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2018 The CivetWeb developers (CREDITS.md) 2 | Copyright (c) 2004-2013 Sergey Lyubka 3 | 4 | Copyright (c) 2013 No Face Press, LLC (Thomas Davis) 5 | 6 | Copyright (c) 2013 F-Secure Corporation 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | -------------------------------------------------------------------------------- /src/civetweb/sha1.inl: -------------------------------------------------------------------------------- 1 | /* 2 | SHA-1 in C 3 | By Steve Reid 4 | 100% Public Domain 5 | 6 | ----------------- 7 | Modified 7/98 8 | By James H. Brown 9 | Still 100% Public Domain 10 | 11 | Corrected a problem which generated improper hash values on 16 bit machines 12 | Routine SHA1Update changed from 13 | void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned int 14 | len) 15 | to 16 | void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned 17 | long len) 18 | 19 | The 'len' parameter was declared an int which works fine on 32 bit machines. 20 | However, on 16 bit machines an int is too small for the shifts being done 21 | against 22 | it. This caused the hash function to generate incorrect values if len was 23 | greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). 24 | 25 | Since the file IO in main() reads 16K at a time, any file 8K or larger would 26 | be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million 27 | "a"s). 28 | 29 | I also changed the declaration of variables i & j in SHA1Update to 30 | unsigned long from unsigned int for the same reason. 31 | 32 | These changes should make no difference to any 32 bit implementations since 33 | an 34 | int and a long are the same size in those environments. 35 | 36 | -- 37 | I also corrected a few compiler warnings generated by Borland C. 38 | 1. Added #include for exit() prototype 39 | 2. Removed unused variable 'j' in SHA1Final 40 | 3. Changed exit(0) to return(0) at end of main. 41 | 42 | ALL changes I made can be located by searching for comments containing 'JHB' 43 | ----------------- 44 | Modified 8/98 45 | By Steve Reid 46 | Still 100% public domain 47 | 48 | 1- Removed #include and used return() instead of exit() 49 | 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) 50 | 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net 51 | 52 | ----------------- 53 | Modified 4/01 54 | By Saul Kravitz 55 | Still 100% PD 56 | Modified to run on Compaq Alpha hardware. 57 | 58 | ----------------- 59 | Modified 07/2002 60 | By Ralph Giles 61 | Still 100% public domain 62 | modified for use with stdint types, autoconf 63 | code cleanup, removed attribution comments 64 | switched SHA1Final() argument order for consistency 65 | use SHA1_ prefix for public api 66 | move public api to sha1.h 67 | */ 68 | 69 | /* 70 | 11/2016 adapted for CivetWeb: 71 | include sha1.h in sha1.c, 72 | rename to sha1.inl 73 | remove unused #ifdef sections 74 | make endian independent 75 | align buffer to 4 bytes 76 | remove unused variable assignments 77 | */ 78 | 79 | /* 80 | Test Vectors (from FIPS PUB 180-1) 81 | "abc" 82 | A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D 83 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 84 | 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 85 | A million repetitions of "a" 86 | 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F 87 | */ 88 | 89 | #include 90 | #include 91 | 92 | typedef struct { 93 | uint32_t state[5]; 94 | uint32_t count[2]; 95 | uint8_t buffer[64]; 96 | } SHA_CTX; 97 | 98 | #define SHA1_DIGEST_SIZE 20 99 | 100 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 101 | 102 | /* blk0() and blk() perform the initial expand. */ 103 | /* I got the idea of expanding during the round function from SSLeay */ 104 | 105 | 106 | typedef union { 107 | uint8_t c[64]; 108 | uint32_t l[16]; 109 | } CHAR64LONG16; 110 | 111 | 112 | static uint32_t 113 | blk0(CHAR64LONG16 *block, int i) 114 | { 115 | static const uint32_t n = 1u; 116 | if ((*((uint8_t *)(&n))) == 1) { 117 | /* little endian / intel byte order */ 118 | block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) 119 | | (rol(block->l[i], 8) & 0x00FF00FF); 120 | } 121 | return block->l[i]; 122 | } 123 | 124 | #define blk(block, i) \ 125 | ((block)->l[(i)&15] = \ 126 | rol((block)->l[((i) + 13) & 15] ^ (block)->l[((i) + 8) & 15] \ 127 | ^ (block)->l[((i) + 2) & 15] ^ (block)->l[(i)&15], \ 128 | 1)) 129 | 130 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 131 | #define R0(v, w, x, y, z, i) \ 132 | z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \ 133 | w = rol(w, 30); 134 | #define R1(v, w, x, y, z, i) \ 135 | z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5); \ 136 | w = rol(w, 30); 137 | #define R2(v, w, x, y, z, i) \ 138 | z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5); \ 139 | w = rol(w, 30); 140 | #define R3(v, w, x, y, z, i) \ 141 | z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 5); \ 142 | w = rol(w, 30); 143 | #define R4(v, w, x, y, z, i) \ 144 | z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5); \ 145 | w = rol(w, 30); 146 | 147 | 148 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 149 | static void 150 | SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) 151 | { 152 | uint32_t a, b, c, d, e; 153 | 154 | /* Must use an aligned, read/write buffer */ 155 | CHAR64LONG16 block[1]; 156 | memcpy(block, buffer, sizeof(block)); 157 | 158 | /* Copy context->state[] to working vars */ 159 | a = state[0]; 160 | b = state[1]; 161 | c = state[2]; 162 | d = state[3]; 163 | e = state[4]; 164 | 165 | /* 4 rounds of 20 operations each. Loop unrolled. */ 166 | R0(a, b, c, d, e, 0); 167 | R0(e, a, b, c, d, 1); 168 | R0(d, e, a, b, c, 2); 169 | R0(c, d, e, a, b, 3); 170 | R0(b, c, d, e, a, 4); 171 | R0(a, b, c, d, e, 5); 172 | R0(e, a, b, c, d, 6); 173 | R0(d, e, a, b, c, 7); 174 | R0(c, d, e, a, b, 8); 175 | R0(b, c, d, e, a, 9); 176 | R0(a, b, c, d, e, 10); 177 | R0(e, a, b, c, d, 11); 178 | R0(d, e, a, b, c, 12); 179 | R0(c, d, e, a, b, 13); 180 | R0(b, c, d, e, a, 14); 181 | R0(a, b, c, d, e, 15); 182 | R1(e, a, b, c, d, 16); 183 | R1(d, e, a, b, c, 17); 184 | R1(c, d, e, a, b, 18); 185 | R1(b, c, d, e, a, 19); 186 | R2(a, b, c, d, e, 20); 187 | R2(e, a, b, c, d, 21); 188 | R2(d, e, a, b, c, 22); 189 | R2(c, d, e, a, b, 23); 190 | R2(b, c, d, e, a, 24); 191 | R2(a, b, c, d, e, 25); 192 | R2(e, a, b, c, d, 26); 193 | R2(d, e, a, b, c, 27); 194 | R2(c, d, e, a, b, 28); 195 | R2(b, c, d, e, a, 29); 196 | R2(a, b, c, d, e, 30); 197 | R2(e, a, b, c, d, 31); 198 | R2(d, e, a, b, c, 32); 199 | R2(c, d, e, a, b, 33); 200 | R2(b, c, d, e, a, 34); 201 | R2(a, b, c, d, e, 35); 202 | R2(e, a, b, c, d, 36); 203 | R2(d, e, a, b, c, 37); 204 | R2(c, d, e, a, b, 38); 205 | R2(b, c, d, e, a, 39); 206 | R3(a, b, c, d, e, 40); 207 | R3(e, a, b, c, d, 41); 208 | R3(d, e, a, b, c, 42); 209 | R3(c, d, e, a, b, 43); 210 | R3(b, c, d, e, a, 44); 211 | R3(a, b, c, d, e, 45); 212 | R3(e, a, b, c, d, 46); 213 | R3(d, e, a, b, c, 47); 214 | R3(c, d, e, a, b, 48); 215 | R3(b, c, d, e, a, 49); 216 | R3(a, b, c, d, e, 50); 217 | R3(e, a, b, c, d, 51); 218 | R3(d, e, a, b, c, 52); 219 | R3(c, d, e, a, b, 53); 220 | R3(b, c, d, e, a, 54); 221 | R3(a, b, c, d, e, 55); 222 | R3(e, a, b, c, d, 56); 223 | R3(d, e, a, b, c, 57); 224 | R3(c, d, e, a, b, 58); 225 | R3(b, c, d, e, a, 59); 226 | R4(a, b, c, d, e, 60); 227 | R4(e, a, b, c, d, 61); 228 | R4(d, e, a, b, c, 62); 229 | R4(c, d, e, a, b, 63); 230 | R4(b, c, d, e, a, 64); 231 | R4(a, b, c, d, e, 65); 232 | R4(e, a, b, c, d, 66); 233 | R4(d, e, a, b, c, 67); 234 | R4(c, d, e, a, b, 68); 235 | R4(b, c, d, e, a, 69); 236 | R4(a, b, c, d, e, 70); 237 | R4(e, a, b, c, d, 71); 238 | R4(d, e, a, b, c, 72); 239 | R4(c, d, e, a, b, 73); 240 | R4(b, c, d, e, a, 74); 241 | R4(a, b, c, d, e, 75); 242 | R4(e, a, b, c, d, 76); 243 | R4(d, e, a, b, c, 77); 244 | R4(c, d, e, a, b, 78); 245 | R4(b, c, d, e, a, 79); 246 | 247 | /* Add the working vars back into context.state[] */ 248 | state[0] += a; 249 | state[1] += b; 250 | state[2] += c; 251 | state[3] += d; 252 | state[4] += e; 253 | } 254 | 255 | 256 | /* SHA1Init - Initialize new context */ 257 | SHA_API void 258 | SHA1_Init(SHA_CTX *context) 259 | { 260 | /* SHA1 initialization constants */ 261 | context->state[0] = 0x67452301; 262 | context->state[1] = 0xEFCDAB89; 263 | context->state[2] = 0x98BADCFE; 264 | context->state[3] = 0x10325476; 265 | context->state[4] = 0xC3D2E1F0; 266 | context->count[0] = context->count[1] = 0; 267 | } 268 | 269 | 270 | SHA_API void 271 | SHA1_Update(SHA_CTX *context, const uint8_t *data, const uint32_t len) 272 | { 273 | uint32_t i, j; 274 | 275 | j = context->count[0]; 276 | if ((context->count[0] += (len << 3)) < j) { 277 | context->count[1]++; 278 | } 279 | context->count[1] += (len >> 29); 280 | j = (j >> 3) & 63; 281 | if ((j + len) > 63) { 282 | i = 64 - j; 283 | memcpy(&context->buffer[j], data, i); 284 | SHA1_Transform(context->state, context->buffer); 285 | for (; i + 63 < len; i += 64) { 286 | SHA1_Transform(context->state, &data[i]); 287 | } 288 | j = 0; 289 | } else { 290 | i = 0; 291 | } 292 | memcpy(&context->buffer[j], &data[i], len - i); 293 | } 294 | 295 | 296 | /* Add padding and return the message digest. */ 297 | SHA_API void 298 | SHA1_Final(unsigned char *digest, SHA_CTX *context) 299 | { 300 | uint32_t i; 301 | uint8_t finalcount[8]; 302 | 303 | for (i = 0; i < 8; i++) { 304 | finalcount[i] = 305 | (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) 306 | & 255); /* Endian independent */ 307 | } 308 | SHA1_Update(context, (uint8_t *)"\x80", 1); 309 | while ((context->count[0] & 504) != 448) { 310 | SHA1_Update(context, (uint8_t *)"\x00", 1); 311 | } 312 | SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ 313 | for (i = 0; i < SHA1_DIGEST_SIZE; i++) { 314 | digest[i] = 315 | (uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); 316 | } 317 | 318 | /* Wipe variables */ 319 | memset(context, '\0', sizeof(*context)); 320 | } 321 | 322 | 323 | /* End of sha1.inl */ 324 | -------------------------------------------------------------------------------- /src/civetweb/timer.inl: -------------------------------------------------------------------------------- 1 | /* This file is part of the CivetWeb web server. 2 | * See https://github.com/civetweb/civetweb/ 3 | * (C) 2014-2018 by the CivetWeb authors, MIT license. 4 | */ 5 | 6 | #if !defined(MAX_TIMERS) 7 | #define MAX_TIMERS MAX_WORKER_THREADS 8 | #endif 9 | 10 | typedef int (*taction)(void *arg); 11 | 12 | struct ttimer { 13 | double time; 14 | double period; 15 | taction action; 16 | void *arg; 17 | }; 18 | 19 | struct ttimers { 20 | pthread_t threadid; /* Timer thread ID */ 21 | pthread_mutex_t mutex; /* Protects timer lists */ 22 | struct ttimer timers[MAX_TIMERS]; /* List of timers */ 23 | unsigned timer_count; /* Current size of timer list */ 24 | }; 25 | 26 | 27 | TIMER_API double 28 | timer_getcurrenttime(void) 29 | { 30 | #if defined(_WIN32) 31 | /* GetTickCount returns milliseconds since system start as 32 | * unsigned 32 bit value. It will wrap around every 49.7 days. 33 | * We need to use a 64 bit counter (will wrap in 500 mio. years), 34 | * by adding the 32 bit difference since the last call to a 35 | * 64 bit counter. This algorithm will only work, if this 36 | * function is called at least once every 7 weeks. */ 37 | static DWORD last_tick; 38 | static uint64_t now_tick64; 39 | 40 | DWORD now_tick = GetTickCount(); 41 | 42 | now_tick64 += ((DWORD)(now_tick - last_tick)); 43 | last_tick = now_tick; 44 | return (double)now_tick64 * 1.0E-3; 45 | #else 46 | struct timespec now_ts; 47 | 48 | clock_gettime(CLOCK_MONOTONIC, &now_ts); 49 | return (double)now_ts.tv_sec + (double)now_ts.tv_nsec * 1.0E-9; 50 | #endif 51 | } 52 | 53 | 54 | TIMER_API int 55 | timer_add(struct mg_context *ctx, 56 | double next_time, 57 | double period, 58 | int is_relative, 59 | taction action, 60 | void *arg) 61 | { 62 | unsigned u, v; 63 | int error = 0; 64 | double now; 65 | 66 | if (ctx->stop_flag) { 67 | return 0; 68 | } 69 | 70 | now = timer_getcurrenttime(); 71 | 72 | /* HCP24: if is_relative = 0 and next_time < now 73 | * action will be called so fast as possible 74 | * if additional period > 0 75 | * action will be called so fast as possible 76 | * n times until (next_time + (n * period)) > now 77 | * then the period is working 78 | * Solution: 79 | * if next_time < now then we set next_time = now. 80 | * The first callback will be so fast as possible (now) 81 | * but the next callback on period 82 | */ 83 | if (is_relative) { 84 | next_time += now; 85 | } 86 | 87 | /* You can not set timers into the past */ 88 | if (next_time < now) { 89 | next_time = now; 90 | } 91 | 92 | pthread_mutex_lock(&ctx->timers->mutex); 93 | if (ctx->timers->timer_count == MAX_TIMERS) { 94 | error = 1; 95 | } else { 96 | /* Insert new timer into a sorted list. */ 97 | /* The linear list is still most efficient for short lists (small 98 | * number of timers) - if there are many timers, different 99 | * algorithms will work better. */ 100 | for (u = 0; u < ctx->timers->timer_count; u++) { 101 | if (ctx->timers->timers[u].time > next_time) { 102 | /* HCP24: moving all timers > next_time */ 103 | for (v = ctx->timers->timer_count; v > u; v--) { 104 | ctx->timers->timers[v] = ctx->timers->timers[v - 1]; 105 | } 106 | break; 107 | } 108 | } 109 | ctx->timers->timers[u].time = next_time; 110 | ctx->timers->timers[u].period = period; 111 | ctx->timers->timers[u].action = action; 112 | ctx->timers->timers[u].arg = arg; 113 | ctx->timers->timer_count++; 114 | } 115 | pthread_mutex_unlock(&ctx->timers->mutex); 116 | return error; 117 | } 118 | 119 | 120 | static void 121 | timer_thread_run(void *thread_func_param) 122 | { 123 | struct mg_context *ctx = (struct mg_context *)thread_func_param; 124 | double d; 125 | unsigned u; 126 | int re_schedule; 127 | struct ttimer t; 128 | 129 | mg_set_thread_name("timer"); 130 | 131 | if (ctx->callbacks.init_thread) { 132 | /* Timer thread */ 133 | ctx->callbacks.init_thread(ctx, 2); 134 | } 135 | 136 | d = timer_getcurrenttime(); 137 | 138 | while (ctx->stop_flag == 0) { 139 | pthread_mutex_lock(&ctx->timers->mutex); 140 | if ((ctx->timers->timer_count > 0) 141 | && (d >= ctx->timers->timers[0].time)) { 142 | t = ctx->timers->timers[0]; 143 | for (u = 1; u < ctx->timers->timer_count; u++) { 144 | ctx->timers->timers[u - 1] = ctx->timers->timers[u]; 145 | } 146 | ctx->timers->timer_count--; 147 | pthread_mutex_unlock(&ctx->timers->mutex); 148 | re_schedule = t.action(t.arg); 149 | if (re_schedule && (t.period > 0)) { 150 | timer_add(ctx, t.time + t.period, t.period, 0, t.action, t.arg); 151 | } 152 | continue; 153 | } else { 154 | pthread_mutex_unlock(&ctx->timers->mutex); 155 | } 156 | 157 | /* 10 ms seems reasonable. 158 | * A faster loop (smaller sleep value) increases CPU load, 159 | * a slower loop (higher sleep value) decreases timer accuracy. 160 | */ 161 | #if defined(_WIN32) 162 | Sleep(10); 163 | #else 164 | usleep(10000); 165 | #endif 166 | 167 | d = timer_getcurrenttime(); 168 | } 169 | 170 | pthread_mutex_lock(&ctx->timers->mutex); 171 | ctx->timers->timer_count = 0; 172 | pthread_mutex_unlock(&ctx->timers->mutex); 173 | } 174 | 175 | 176 | #if defined(_WIN32) 177 | static unsigned __stdcall timer_thread(void *thread_func_param) 178 | { 179 | timer_thread_run(thread_func_param); 180 | return 0; 181 | } 182 | #else 183 | static void * 184 | timer_thread(void *thread_func_param) 185 | { 186 | struct sigaction sa; 187 | 188 | /* Ignore SIGPIPE */ 189 | memset(&sa, 0, sizeof(sa)); 190 | sa.sa_handler = SIG_IGN; 191 | sigaction(SIGPIPE, &sa, NULL); 192 | 193 | timer_thread_run(thread_func_param); 194 | return NULL; 195 | } 196 | #endif /* _WIN32 */ 197 | 198 | 199 | TIMER_API int 200 | timers_init(struct mg_context *ctx) 201 | { 202 | /* Initialize timers data structure */ 203 | ctx->timers = 204 | (struct ttimers *)mg_calloc_ctx(sizeof(struct ttimers), 1, ctx); 205 | 206 | if (!ctx->timers) { 207 | return -1; 208 | } 209 | 210 | /* Initialize mutex */ 211 | if (0 != pthread_mutex_init(&ctx->timers->mutex, NULL)) { 212 | mg_free((void *)(ctx->timers)); 213 | return -1; 214 | } 215 | 216 | /* For some systems timer_getcurrenttime does some initialization 217 | * during the first call. Call it once now, ignore the result. */ 218 | (void)timer_getcurrenttime(); 219 | 220 | /* Start timer thread */ 221 | mg_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid); 222 | 223 | return 0; 224 | } 225 | 226 | 227 | TIMER_API void 228 | timers_exit(struct mg_context *ctx) 229 | { 230 | if (ctx->timers) { 231 | pthread_mutex_lock(&ctx->timers->mutex); 232 | ctx->timers->timer_count = 0; 233 | 234 | mg_join_thread(ctx->timers->threadid); 235 | 236 | /* TODO: Do we really need to unlock the mutex, before 237 | * destroying it, if it's destroyed by the thread currently 238 | * owning the mutex? */ 239 | pthread_mutex_unlock(&ctx->timers->mutex); 240 | (void)pthread_mutex_destroy(&ctx->timers->mutex); 241 | mg_free(ctx->timers); 242 | } 243 | } 244 | 245 | 246 | /* End of timer.inl */ 247 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | * 5 | * This file contains logging functions and controls. 6 | */ 7 | 8 | #include 9 | #include 10 | #include "log.h" 11 | 12 | /* Default logging level is INFO */ 13 | int log_level = LOG_LEVEL_INFO; 14 | 15 | void mudc_log (int level, char *format, ...) 16 | { 17 | va_list arguments; 18 | 19 | if (level <= log_level) { 20 | 21 | va_start(arguments, format); 22 | 23 | vfprintf(stdout, format, arguments); 24 | fflush(stdout); 25 | } 26 | } 27 | 28 | /* 29 | * mudc_log_status prints out messages regardless of debug level. 30 | */ 31 | void mudc_log_status (char *format, ...) 32 | { 33 | va_list arguments; 34 | 35 | va_start(arguments, format); 36 | 37 | vfprintf(stdout, format, arguments); 38 | fflush(stdout); 39 | } 40 | 41 | void DumpHex(const void* data, size_t size) { 42 | char ascii[17]; 43 | size_t i, j; 44 | ascii[16] = '\0'; 45 | for (i = 0; i < size; ++i) { 46 | printf("%02X ", ((unsigned char*)data)[i]); 47 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { 48 | ascii[i % 16] = ((unsigned char*)data)[i]; 49 | } else { 50 | ascii[i % 16] = '.'; 51 | } 52 | if ((i+1) % 8 == 0 || i+1 == size) { 53 | printf(" "); 54 | if ((i+1) % 16 == 0) { 55 | printf("| %s \n", ascii); 56 | } else if (i+1 == size) { 57 | ascii[(i+1) % 16] = '\0'; 58 | if ((i+1) % 16 <= 8) { 59 | printf(" "); 60 | } 61 | for (j = (i+1) % 16; j < 16; ++j) { 62 | printf(" "); 63 | } 64 | printf("| %s \n", ascii); 65 | } 66 | } 67 | } 68 | printf("\n"); 69 | } 70 | 71 | void mudc_log_hex (int level, const char *func, int line, 72 | char *context, char *buf, int buf_len) 73 | { 74 | if (level <= log_level) { 75 | 76 | fprintf(stdout, "***MUDC [DEBUG][%s:%d]--> %s (length %d)\n", 77 | func, line, context, buf_len); 78 | DumpHex(buf, buf_len); 79 | fflush(stdout); 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | 6 | enum { 7 | LOG_LEVEL_NONE = 0, 8 | LOG_LEVEL_ERROR = 1, 9 | LOG_LEVEL_INFO = 2, 10 | LOG_LEVEL_DEBUG = 3, 11 | LOG_LEVEL_ALL = 4, 12 | }; 13 | 14 | 15 | #define MUDC_LOG_INFO(format, args ...) do { \ 16 | mudc_log(LOG_LEVEL_INFO, "***MUDC [INFO][%s:%d]--> " format "\n", \ 17 | __func__, __LINE__, ##args); \ 18 | } while (0) 19 | 20 | #define MUDC_LOG_ERR(format, args ...) do { \ 21 | mudc_log(LOG_LEVEL_ERROR, "***MUDC [ERROR][%s:%d]--> " format "\n", \ 22 | __func__, __LINE__, ##args); \ 23 | } while (0) 24 | 25 | #define MUDC_LOG_DEBUG(format, args ...) do { \ 26 | mudc_log(LOG_LEVEL_DEBUG, "***MUDC [DEBUG][%s:%d]--> " format "\n", \ 27 | __func__, __LINE__, ##args); \ 28 | } while (0) 29 | 30 | #define MUDC_LOG_DEBUG_HEX(context_str, buf, buf_len) do { \ 31 | mudc_log_hex(LOG_LEVEL_DEBUG, __func__, __LINE__, context_str, buf, buf_len); \ 32 | } while (0) 33 | 34 | #define MUDC_LOG_WRITE_DATA(nc, format, args ...) do { \ 35 | MUDC_LOG_INFO(format, ##args); \ 36 | mg_printf(nc, format, ##args); \ 37 | } while (0) 38 | 39 | #define MUDC_LOG_STATUS(format, args ...) do { \ 40 | mudc_log_status("***MUDC [STATUS][%s:%d]--> " format "\n", \ 41 | __func__, __LINE__, ##args); \ 42 | } while (0) 43 | 44 | extern int log_level; 45 | 46 | extern void mudc_log (int level, char *format, ...); 47 | extern void mudc_log_hex (int level, const char *func, int line, char *context, 48 | char *buf, int buf_len); 49 | extern void mudc_log_status (char *format, ...); 50 | -------------------------------------------------------------------------------- /src/mud_fs_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "log.h" 10 | 11 | /* 12 | * Memory for callbacks 13 | */ 14 | struct MemoryStruct { 15 | char *memory; 16 | size_t size; 17 | }; 18 | 19 | static size_t 20 | WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) 21 | { 22 | size_t realsize = size * nmemb; 23 | struct MemoryStruct *mem = (struct MemoryStruct *)userp; 24 | 25 | mem->memory = realloc(mem->memory, mem->size + realsize + 1); 26 | if (mem->memory == NULL) { 27 | /* out of memory! */ 28 | MUDC_LOG_ERR("not enough memory (realloc returned NULL)\n"); 29 | return 0; 30 | } 31 | 32 | memcpy(&(mem->memory[mem->size]), contents, realsize); 33 | mem->size += realsize; 34 | mem->memory[mem->size] = 0; 35 | 36 | return realsize; 37 | } 38 | 39 | static size_t validateheaders(void *ptr, size_t size, size_t nmemb, 40 | void *userdata) 41 | { 42 | int s=0,r=0; 43 | char str[10]; 44 | int code = 0; 45 | int ret = size * nmemb; /* Return's OK. Any other value with be an error. */ 46 | char contenttype[100]; 47 | 48 | char *header = (char *)userdata; 49 | 50 | MUDC_LOG_INFO("Header: %s", ptr); 51 | 52 | /* 53 | * Check the HTTP return code. 54 | */ 55 | s = strncmp(ptr, "HTTP/", 5); 56 | if (s == 0) { 57 | /* 58 | * Check for the code. The 'str' variable is unused, but 59 | * provides a means to capture the HTTP code, regardless of 60 | * HTTP version. (sscanf() uses its own parsing languague 61 | * rather then regexp.) 62 | */ 63 | r = sscanf(ptr, "HTTP/%[^ ]%d OK", str, &code); 64 | if (r == 0) { 65 | MUDC_LOG_ERR("HTTP code not found\n"); 66 | ret = 0; 67 | } else if (code != 200) { 68 | MUDC_LOG_ERR("Unexpected return code: %d\n", code); 69 | ret = 0; 70 | } 71 | MUDC_LOG_INFO("str: %s\n", str); 72 | } 73 | 74 | s = sscanf(ptr, "Content-Type: %s\n", contenttype); 75 | if (s) { 76 | /* 77 | * Verify that the retrieved content-type is the expected one. 78 | */ 79 | if (strncmp(contenttype, header, strlen(header))) { 80 | /* 81 | * Oops, the header is not the expected one. 82 | * 83 | * The web server might not know about the new Content-Type 84 | * strings defined for MUD, so accept approximately-correct 85 | * responses with a warning. 86 | */ 87 | if (strstr(contenttype, "json") || strstr(contenttype,"plain")) { 88 | if (strstr(header, "json") ) { 89 | MUDC_LOG_INFO("Warning: Web server sent unexpected (but " 90 | "similar) Content-Type."); 91 | MUDC_LOG_INFO(" expected=%s\n", header); 92 | MUDC_LOG_INFO(" returned=%s\n", contenttype); 93 | } else { 94 | MUDC_LOG_ERR("Error: Web server sent unexpected " 95 | "Content-Type."); 96 | MUDC_LOG_ERR(" expected=%s\n", header); 97 | MUDC_LOG_ERR(" returned=%s\n", contenttype); 98 | ret = 0; 99 | } 100 | } else if (strstr(contenttype, "pkcs7")) { 101 | if (strstr(header, "pkcs7")) { 102 | MUDC_LOG_INFO("Warning: Web server sent unexpected (but " 103 | "similar) Content-Type."); 104 | MUDC_LOG_INFO(" expected=%s\n", header); 105 | MUDC_LOG_INFO(" returned=%s\n", contenttype); 106 | } else { 107 | MUDC_LOG_ERR("Error: Web server sent unexpected " 108 | "Content-Type."); 109 | MUDC_LOG_ERR(" expected=%s\n", header); 110 | MUDC_LOG_ERR(" returned=%s\n", contenttype); 111 | ret = 0; 112 | } 113 | } else { 114 | MUDC_LOG_ERR("Error: Web server sent unexpected Content-Type."); 115 | MUDC_LOG_ERR(" expected=%s\n", header); 116 | MUDC_LOG_ERR(" returned=%s\n", contenttype); 117 | ret = 0; 118 | } 119 | } 120 | } 121 | 122 | return ret; 123 | } 124 | 125 | char *fetch_file(CURL *curl, char *get_url, 126 | int *response_len, char *response_app_string, 127 | char *fs_ca_cert) 128 | { 129 | CURLcode res = CURLE_OK; 130 | struct curl_slist *headers = NULL; 131 | struct MemoryStruct response; 132 | char exp_response_header[100]; 133 | char *retbuf=NULL; 134 | 135 | memset(exp_response_header, 0, sizeof(exp_response_header)); 136 | memset(&response, 0, sizeof(response)); 137 | 138 | 139 | sprintf(exp_response_header, "application/%s", response_app_string); 140 | 141 | response.memory = malloc(1); /* be grown as needed by the realloc above */ 142 | response.size = 0; /* no data at this point */ 143 | 144 | 145 | /* 146 | * There should be a "verbose" flag to determine whether VERBOSE is 1L 147 | * and whether STDERR is defined at all. 148 | */ 149 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); /* Set to 1L for more output */ 150 | curl_easy_setopt(curl, CURLOPT_STDERR, stdout); /* See msgs on stdout */ 151 | curl_easy_setopt(curl, CURLOPT_URL, get_url); 152 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 153 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, validateheaders); 154 | curl_easy_setopt(curl, CURLOPT_HEADERDATA, exp_response_header); 155 | curl_easy_setopt(curl, CURLOPT_HEADER, 0L); /* Don't inc. hdrs. in resp. */ 156 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); 157 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); 158 | 159 | curl_easy_setopt(curl,CURLOPT_CAPATH,"/etc/ssl/certs"); 160 | if ( fs_ca_cert != NULL) 161 | curl_easy_setopt(curl, CURLOPT_CAINFO, fs_ca_cert); 162 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 163 | 164 | if (!strcmp(response_app_string,"mud+json")) { 165 | /* headers = curl_slist_append(headers, "Accept: application/mud+json");*/ 166 | } else if (!strcmp(response_app_string, "pkcs7-signature")) { 167 | headers = curl_slist_append(headers, 168 | "Accept: application/pkcs7-signature"); 169 | } else { 170 | MUDC_LOG_ERR("Request is not a .json file or signature file\n"); 171 | return NULL; 172 | } 173 | headers = curl_slist_append(headers, "Content-Type: application/mud+json"); 174 | headers = curl_slist_append(headers, "Accept-Language: en"); 175 | headers = curl_slist_append(headers, "User-Agent: prototype-mud-manager"); 176 | 177 | res = curl_easy_perform(curl); 178 | /* check for errors */ 179 | if (res != CURLE_OK) { 180 | if (res == CURLE_RECV_ERROR) { 181 | MUDC_LOG_INFO("Ignoring the server error."); 182 | } else { 183 | MUDC_LOG_ERR("curl_easy_perform() failed: %s\n", 184 | curl_easy_strerror(res)); 185 | curl_slist_free_all(headers); 186 | free(response.memory); 187 | return NULL; 188 | } 189 | } 190 | 191 | /* 192 | * Now, our response.memory points to a memory block that is response.size 193 | * bytes big and contains the result. 194 | */ 195 | *response_len = response.size; 196 | retbuf = calloc(response.size + 1, sizeof(char)); 197 | memcpy(retbuf, response.memory, response.size); 198 | free(response.memory); 199 | curl_slist_free_all(headers); 200 | 201 | return retbuf; 202 | } 203 | 204 | -------------------------------------------------------------------------------- /src/mud_fs_client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | 6 | char *fetch_file(CURL *curl, char *get_url, 7 | int *response_len, char *response_app_string, 8 | char *fs_ca_cert); 9 | -------------------------------------------------------------------------------- /src/mud_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2019 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef _MUD_MANAGER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "openssl/dh.h" 21 | #include "openssl/ec.h" 22 | #include "openssl/evp.h" 23 | #include "openssl/ecdsa.h" 24 | 25 | #pragma GCC diagnostic push // suppress specific warning from 3rd-party code 26 | #pragma GCC diagnostic ignored "-Wexpansion-to-defined" 27 | #include 28 | #pragma GCC diagnostic pop 29 | #include 30 | #include 31 | #include "acl.h" 32 | #include "log.h" 33 | #include "sessions.h" 34 | #include "acl_types.h" 35 | #include "mud_fs_client.h" 36 | 37 | #define DACL_INGRESS_EGRESS 0 38 | #define DACL_INGRESS_ONLY 1 39 | #define MAX_BUF 4096 40 | #define MAX_ACL_STATEMENTS 50 41 | #define INITIAL_ACE_STATEMENTS 50 42 | #define MAX_ACE_STATEMENTS 300 43 | 44 | #define FROM_DEVICE 0 45 | #define TO_DEVICE 1 46 | 47 | #define SRCPORT 1 48 | #define DSTPORT 2 49 | 50 | #define MAXREQURI 255 51 | 52 | 53 | #define IS_AUTHORITY 0 54 | #define IS_URL 1 55 | 56 | 57 | typedef struct _vlan_info { 58 | int vlan; 59 | char *mud_url; 60 | char *v4_nw; 61 | char *v6_nw; 62 | } vlan_info; 63 | 64 | typedef struct _addrlist { 65 | char *address; 66 | struct _addrlist *next; 67 | } addrlist; 68 | 69 | typedef struct _request_context { 70 | struct mg_connection *in; 71 | char *uri; 72 | char *mac_addr; 73 | char *sess_id; 74 | char *nas; 75 | char *signed_mud; 76 | int signed_mud_len; 77 | char *orig_mud; 78 | int orig_mud_len; 79 | int masaurirequest; 80 | bool send_client_response; 81 | bool needs_mycontroller; 82 | } request_context; 83 | 84 | typedef struct _manufacturer_list { 85 | char* authority; 86 | char* uri; 87 | char* https_port; 88 | char* certfile; 89 | char* web_certfile; 90 | X509 *cert; 91 | X509 *web_cert; 92 | int vlan; 93 | char* vlan_nw_v4; 94 | char* vlan_nw_v6; 95 | char* my_ctrl_v4; 96 | char* my_ctrl_v6; 97 | char* local_nw_v4; 98 | char* local_nw_v6; 99 | } manufacturer_list; 100 | 101 | #define _MUD_MANAGER_H 1 102 | #endif /* _MUD_MANAGER_H */ 103 | -------------------------------------------------------------------------------- /src/mud_test_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | int s_exit_flag=0; 16 | 17 | #define MAX_STR_LEN 255 18 | 19 | #define WEBSERVERMAX 40 20 | #define MUDFILEMAX 80 21 | #define MACADDRMAX 15 22 | #define NASMAX 15 23 | #define SESSMAX 15 24 | 25 | char mudcontroller_ip[WEBSERVERMAX]; 26 | int mudcontroller_port; 27 | 28 | int test_client_get_dacl(char* uri, char* aclname); 29 | 30 | /* 31 | * Memory for callbacks 32 | */ 33 | struct MemoryStruct { 34 | char *memory; 35 | size_t size; 36 | }; 37 | 38 | static size_t 39 | WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) 40 | { 41 | size_t realsize = size * nmemb; 42 | struct MemoryStruct *mem = (struct MemoryStruct *)userp; 43 | 44 | mem->memory = realloc(mem->memory, mem->size + realsize + 1); 45 | if (mem->memory == NULL) { 46 | /* out of memory! */ 47 | printf("not enough memory (realloc returned NULL)\n"); 48 | return 0; 49 | } 50 | 51 | memcpy(&(mem->memory[mem->size]), contents, realsize); 52 | mem->size += realsize; 53 | mem->memory[mem->size] = 0; 54 | 55 | return realsize; 56 | } 57 | 58 | static size_t validateheaders(void *ptr, size_t size, size_t nmemb, 59 | void *userdata) 60 | { 61 | int s,r; 62 | int code = 0; 63 | char str[10]; 64 | int ret = size * nmemb; /* OK */ 65 | char contenttype[100]; 66 | 67 | char *header = (char *)userdata; 68 | 69 | /* 70 | * Check the HTTP return code. 71 | */ 72 | s = strncmp(ptr, "HTTP/", 5); 73 | if (s == 0) { 74 | /* 75 | * Check for the code. The 'str' variable i unused, but 76 | * provides a sort of regular expression way to capture 77 | * the code, regardless of HTTP version. 78 | */ 79 | r = sscanf(ptr, "HTTP/%[^ ]%d OK", str, &code); 80 | if (r == 0) { 81 | printf("HTTP code not found\n"); 82 | ret = 0; 83 | } else if (code != 200) { 84 | printf("Unexpected return code: %d\n", code); 85 | ret = 0; 86 | } 87 | } 88 | 89 | s = sscanf(ptr, "Content-Type: %s\n", contenttype); 90 | if (s) { 91 | /* 92 | * Verify that the retrieved content-type is the expected one. 93 | */ 94 | if (strncmp(contenttype, header, strlen(header))) { 95 | printf(" Unexpected Content-Type: %s\n", contenttype); 96 | ret = 0; 97 | } 98 | } 99 | 100 | return ret; 101 | } 102 | 103 | static void test_client_initialize() 104 | { 105 | OpenSSL_add_all_algorithms(); 106 | } 107 | 108 | char *fetch_json_info(CURL *curl, char *get_url, char *request_str, 109 | int *response_len, char *response_app_string) 110 | { 111 | CURLcode res; 112 | struct curl_slist *headers = NULL; 113 | struct MemoryStruct response; 114 | char exp_response_header[100]; 115 | 116 | sprintf(exp_response_header, "application/%s", response_app_string); 117 | 118 | response.memory = malloc(1); /* be grown as needed by the realloc above */ 119 | response.size = 0; /* no data at this point */ 120 | 121 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); /* Set to 1L for more output */ 122 | curl_easy_setopt(curl, CURLOPT_URL, get_url); 123 | headers = curl_slist_append(headers, "Accept: application/json"); 124 | headers = curl_slist_append(headers, "Content-Type: application/json"); 125 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 126 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, validateheaders); 127 | curl_easy_setopt(curl, CURLOPT_HEADERDATA, exp_response_header); 128 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_str); 129 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); 130 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); 131 | 132 | res = curl_easy_perform(curl); 133 | /* check for errors */ 134 | if (res != CURLE_OK) { 135 | fprintf(stderr, "curl_easy_perform() failed: %s\n", 136 | curl_easy_strerror(res)); 137 | curl_slist_free_all(headers); 138 | free(response.memory); 139 | return NULL; 140 | } 141 | 142 | /* 143 | * Now, our response.memory points to a memory block that is response.size 144 | * bytes big and contains the result. 145 | */ 146 | *response_len = response.size; 147 | 148 | return response.memory; 149 | } 150 | 151 | char *create_uri(char *command) 152 | { 153 | char *get_url = malloc(MAX_STR_LEN); 154 | 155 | if (mudcontroller_port) { 156 | sprintf(get_url, "http://%s:%d/%s", mudcontroller_ip, 157 | mudcontroller_port, command); 158 | } else { 159 | sprintf(get_url, "http://%s/%s", mudcontroller_ip, command); 160 | } 161 | return get_url; 162 | } 163 | 164 | int test_client_get_acls(CURL *curl, char* uri, char* mac_addr, char* nas, 165 | char* sess_id) 166 | { 167 | char *request_str; 168 | cJSON *jsonRequest; 169 | char *get_url; 170 | int status = 0; 171 | char *response; 172 | int response_len = 0; 173 | int i, j; 174 | cJSON* res_json, *acl_name_array, *acl_array; 175 | char *aclname, *full_aclname, *acl; 176 | 177 | jsonRequest = cJSON_CreateObject(); 178 | if (uri != NULL) { 179 | cJSON_AddItemToObject(jsonRequest, "MUD_URI", cJSON_CreateString((char*)uri)); 180 | } 181 | if (mac_addr != NULL) { 182 | cJSON_AddItemToObject(jsonRequest, "MAC_ADDR", cJSON_CreateString((char*)mac_addr)); 183 | } 184 | if (nas != NULL) { 185 | cJSON_AddItemToObject(jsonRequest, "NAS", cJSON_CreateString((char*)nas)); 186 | } 187 | if (sess_id != NULL) { 188 | cJSON_AddItemToObject(jsonRequest, "SESS_ID", cJSON_CreateString((char*)sess_id)); 189 | } 190 | 191 | request_str = cJSON_Print(jsonRequest); 192 | 193 | get_url = create_uri("getaclname"); 194 | printf("\nStarting RESTful client against %s\n", get_url); 195 | printf(" with request %s\n", request_str); 196 | 197 | /* 198 | * Request an ACL name for this MUD URL. 199 | */ 200 | response = fetch_json_info(curl, get_url, request_str, &response_len, 201 | "aclname"); 202 | if ((response_len == 0) && (!response)) { 203 | fprintf(stderr, "Aborting. No ACL name found.\n"); 204 | cJSON_Delete(jsonRequest); 205 | curl_easy_cleanup(curl); 206 | return 1; 207 | } 208 | cJSON_Delete(jsonRequest); 209 | free(get_url); 210 | get_url = NULL; 211 | 212 | printf("Got ACL Names\n"); 213 | res_json = cJSON_Parse((char*)response); 214 | acl_name_array = cJSON_GetObjectItem(res_json, "Cisco-AVPair"); 215 | for (i=0; i< cJSON_GetArraySize(acl_name_array); i++) { 216 | full_aclname = cJSON_GetArrayItem(acl_name_array, i)->valuestring; 217 | printf("Full ACL Name %d: %s\n", i, full_aclname); 218 | 219 | /* 220 | * Request the ACL for the ACL name. The requested ACL name 221 | * must be simply the ACL name, without the DACL framework. 222 | */ 223 | aclname = index(full_aclname, '='); 224 | if (!aclname) { 225 | printf("Malformed ACL name: no = sign.\n"); 226 | return 1; 227 | } 228 | aclname++; /* Skip past '=' */ 229 | printf("ACLname: %s\n", aclname); 230 | 231 | jsonRequest = cJSON_CreateObject(); 232 | cJSON_AddItemToObject(jsonRequest, "ACL_NAME", 233 | cJSON_CreateString(aclname)); 234 | request_str = cJSON_Print(jsonRequest); 235 | 236 | get_url = create_uri("getaclpolicy"); 237 | 238 | printf("\nStarting RESTful client against %s with request %s\n", 239 | get_url, request_str); 240 | response = fetch_json_info(curl, get_url, request_str, &response_len, 241 | "dacl"); 242 | if ((response_len == 0) && (!response)) { 243 | fprintf(stderr, "Aborting. No ACL name found.\n"); 244 | return 1; 245 | } 246 | cJSON_Delete(jsonRequest); 247 | free(get_url); 248 | 249 | res_json = cJSON_Parse((char*)response); 250 | /* 251 | * Validate that the Username is the ACL name. 252 | */ 253 | printf("Username: %s\n", 254 | cJSON_GetObjectItem(res_json, "User-Name")->valuestring); 255 | printf("Got DACL contents:\n"); 256 | acl_array = cJSON_GetObjectItem(res_json, "Cisco-AVPair"); 257 | for (j=0; j< cJSON_GetArraySize(acl_array); j++) { 258 | acl = cJSON_GetArrayItem(acl_array,j)->valuestring; 259 | printf("\tACE: %s\n", acl); 260 | } 261 | } 262 | 263 | free(response); 264 | 265 | /* we're done with libcurl, so clean it up */ 266 | curl_easy_cleanup(curl); 267 | 268 | return status; 269 | } 270 | 271 | int test_client_get_masauri(CURL *curl, char* uri) 272 | { 273 | char *request_str; 274 | int status=0; 275 | cJSON *jsonRequest, *res_json; 276 | char *get_url; 277 | char *response; 278 | int response_len = 0; 279 | 280 | jsonRequest = cJSON_CreateObject(); 281 | cJSON_AddItemToObject(jsonRequest, "MUD_URI", 282 | cJSON_CreateString((char*)uri)); 283 | 284 | request_str = cJSON_Print(jsonRequest); 285 | 286 | get_url = create_uri("getmasauri"); 287 | printf("\nStarting RESTful client against %s\n", get_url); 288 | 289 | /* 290 | * Request an ACL name for this MUD URL. 291 | */ 292 | response = fetch_json_info(curl, get_url, request_str, &response_len, 293 | "masauri"); 294 | if ((response_len == 0) && (!response)) { 295 | fprintf(stderr, "Aborting. No MASA Server found.\n"); 296 | return 1; 297 | } 298 | cJSON_Delete(jsonRequest); 299 | free(get_url); 300 | 301 | res_json = cJSON_Parse((char*)response); 302 | cJSON_Delete(jsonRequest); 303 | 304 | printf("Got MASA URI: %s", 305 | cJSON_GetObjectItem(res_json, "MASA-URI")->valuestring); 306 | 307 | return status; 308 | } 309 | 310 | void usage(char *filename) 311 | { 312 | fprintf(stderr, "Usage: %s [-b ] [-m] -f mudfilename " 313 | "-w -c\n", filename); 314 | return; 315 | } 316 | 317 | int main(int argc, char *argv[]) 318 | { 319 | int testmasa = 0; 320 | int testmud = 0; 321 | int testmudwithmac = 0; 322 | char webserver[WEBSERVERMAX]; 323 | char mudfile[MUDFILEMAX]; 324 | char mac_addr[MACADDRMAX]; 325 | char nas[NASMAX]; 326 | char sess_id[SESSMAX]; 327 | int opt; 328 | char url[14+WEBSERVERMAX+MUDFILEMAX]; 329 | CURL *curl; 330 | 331 | memset(webserver, 0, WEBSERVERMAX); 332 | memset(mudfile, 0, MUDFILEMAX); 333 | memset(mac_addr, 0, MACADDRMAX); 334 | memset(nas, 0, NASMAX); 335 | memset(sess_id, 0, SESSMAX); 336 | 337 | while ((opt = getopt(argc, argv, "a:n:s:bf:mw:c:p:")) != -1) { 338 | switch (opt) { 339 | case 'a': 340 | testmudwithmac = 1; 341 | strncpy(mac_addr, optarg, MACADDRMAX); 342 | break; 343 | case 'b': 344 | testmasa = 1; 345 | break; 346 | case 'f': 347 | strncpy(mudfile, optarg, MUDFILEMAX); 348 | break; 349 | case 'n': 350 | strncpy(nas, optarg, NASMAX); 351 | break; 352 | case 'm': 353 | testmud = 1; 354 | break; 355 | case 's': 356 | strncpy(sess_id, optarg, SESSMAX); 357 | break; 358 | case 'w': 359 | strncpy(webserver, optarg, WEBSERVERMAX); 360 | break; 361 | case 'c': 362 | strncpy(mudcontroller_ip, optarg, WEBSERVERMAX); 363 | break; 364 | case 'p': 365 | mudcontroller_port = atoi(optarg); 366 | break; 367 | default: 368 | usage(argv[0]); 369 | exit(1); 370 | } 371 | } 372 | 373 | if ((webserver[0] == 0) || (mudfile[0] == 0)) { 374 | usage(argv[0]); 375 | exit(1); 376 | } 377 | 378 | /* 379 | * Default is to test for a MUD file. 380 | */ 381 | if (!testmasa && !testmud) { 382 | testmud = 1; 383 | } 384 | 385 | test_client_initialize(); 386 | 387 | /* 388 | * Build URL from args. Save the webserver info too. 389 | */ 390 | strcpy(url, "https://"); 391 | strncat(url, webserver, WEBSERVERMAX); 392 | strncat(url, "/", 1); 393 | strncat(url, mudfile, MUDFILEMAX); 394 | 395 | curl = curl_easy_init(); 396 | 397 | if (testmasa) { 398 | test_client_get_masauri(curl, url); 399 | } 400 | 401 | if (testmudwithmac) { 402 | test_client_get_acls(curl, url, mac_addr, nas, sess_id); 403 | } else if (testmud) { 404 | printf ("URL: %s\n", url); 405 | test_client_get_acls(curl, url, NULL, NULL, NULL); 406 | } 407 | 408 | return(0); 409 | } 410 | 411 | 412 | -------------------------------------------------------------------------------- /src/sessions.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | * 5 | * The sessions structure keeps track of MAC addresses and 6 | * dynamic information that has been disovered about those MAC addresses 7 | * since the program was started. 8 | */ 9 | 10 | #include 11 | #include 12 | #include "log.h" 13 | #include "sessions.h" 14 | 15 | sessions_info *sess_list = NULL; 16 | 17 | int add_session(const char* mac, const char* sessid, const char* nas, 18 | const char *uri) 19 | { 20 | int ret = SESS_ERROR; 21 | sessions_info *tmp=NULL, *new=NULL, *prev=NULL; 22 | 23 | if (mac == NULL || sessid == NULL || nas == NULL) { 24 | MUDC_LOG_ERR("invalid parameters"); 25 | return SESS_ERROR; 26 | } 27 | 28 | if (sess_list == NULL) { 29 | sess_list = (sessions_info*) calloc(1, sizeof(struct _sessions_info)); 30 | strncpy(sess_list->mac_addr, mac, sizeof(sess_list->mac_addr) - 1); 31 | strncpy(sess_list->sessid, sessid, sizeof(sess_list->sessid) - 1); 32 | strncpy(sess_list->nas, nas, sizeof(sess_list->nas) - 1); 33 | strncpy(sess_list->uri, uri, sizeof(sess_list->uri) - 1); 34 | ret = SESS_ADDED; 35 | } else { 36 | tmp = sess_list; 37 | prev = sess_list; 38 | while (tmp != NULL) { 39 | if (strcmp(tmp->mac_addr, mac) == 0) { 40 | if (strcmp(tmp->sessid, sessid) != 0) { 41 | strncpy(tmp->sessid, sessid, sizeof(tmp->sessid) - 1); 42 | } 43 | ret = SESS_EXISTS; 44 | } 45 | prev = tmp; 46 | tmp = tmp->next; 47 | } 48 | if (ret != SESS_EXISTS) { 49 | new = (sessions_info*) calloc(1, sizeof(struct _sessions_info)); 50 | strncpy(new->mac_addr, mac, sizeof(new->mac_addr) - 1); 51 | strncpy(new->sessid, sessid, sizeof(new->sessid) - 1); 52 | strncpy(new->nas, nas, sizeof(new->nas) - 1); 53 | prev->next = new; 54 | ret = SESS_ADDED; 55 | } 56 | } 57 | return ret; 58 | } 59 | 60 | void remove_session(char* mac) 61 | { 62 | sessions_info *tmp=NULL, *prev=NULL; 63 | 64 | if (mac == NULL) { 65 | MUDC_LOG_ERR("invalid parameters"); 66 | return; 67 | } 68 | 69 | tmp = sess_list; 70 | while (tmp != NULL) { 71 | if (strcmp(tmp->mac_addr, mac) == 0) { 72 | if (prev == NULL) { 73 | sess_list = NULL; 74 | } else { 75 | prev->next = tmp->next; 76 | } 77 | free(tmp); 78 | break; 79 | } else { 80 | prev = tmp; 81 | tmp = tmp->next; 82 | } 83 | } 84 | } 85 | 86 | sessions_info *find_session(char *mac) 87 | { 88 | sessions_info *tmp=NULL; 89 | int found = 0; 90 | 91 | if (mac == NULL) { 92 | MUDC_LOG_ERR("invalid parameters"); 93 | return NULL; 94 | } 95 | 96 | tmp = sess_list; 97 | while (tmp != NULL) { 98 | if (strcmp(tmp->mac_addr, mac) == 0) { 99 | found = 1; 100 | break; 101 | } 102 | tmp = tmp->next; 103 | } 104 | if (found) { 105 | return tmp; 106 | } else { 107 | MUDC_LOG_ERR("Error: Session for this MAC is not found"); 108 | return NULL; 109 | } 110 | } 111 | 112 | -------------------------------------------------------------------------------- /src/sessions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Cisco and/or its affiliates. 3 | * All rights reserved. 4 | */ 5 | 6 | 7 | #define SESS_ERROR 0 8 | #define SESS_ADDED 1 9 | #define SESS_EXISTS 2 10 | 11 | 12 | typedef struct _sessions_info { 13 | char mac_addr[50+1]; 14 | char sessid[25+1]; 15 | char nas[50+1]; 16 | char uri[255+1]; 17 | struct _sessions_info *next; 18 | } sessions_info; 19 | 20 | extern sessions_info *sess_list; 21 | 22 | extern int add_session(const char* mac, const char* sessid, const char* nas, 23 | const char *uri); 24 | extern void remove_session(char* mac); 25 | extern sessions_info *find_session(char *mac); 26 | -------------------------------------------------------------------------------- /webui/.#style.css: -------------------------------------------------------------------------------- 1 | lear@upstairs.ofcourseimright.com.10495:1545385745 -------------------------------------------------------------------------------- /webui/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | if BUILDUI 5 | 6 | webdir=@WEBUI@ 7 | web_DATA=funcs.php edit.css index.php mm.js mud-edit.php mud-home.php \ 8 | show-acl-policy.php statics.php style.css 9 | 10 | install-data-hook: 11 | @echo You must now run composer in $(webdir) as follows: 12 | @echo @COMPOSER@ require mongodb/mongodb 13 | @echo 14 | @echo This may not be done as root. 15 | 16 | endif 17 | -------------------------------------------------------------------------------- /webui/edit.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | width: 80%; 4 | margin-right: 70px; 5 | margin-left: 70px; 6 | margin-top: 40px; 7 | } 8 | 9 | table, td { 10 | border: 1px solid #aaa; 11 | } 12 | 13 | table tr td:first-child { 14 | background-color:#176264; 15 | color: white; 16 | } 17 | 18 | body { 19 | font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; 20 | } 21 | -------------------------------------------------------------------------------- /webui/funcs.php: -------------------------------------------------------------------------------- 1 | . 5 | * The type can be text or a number. 6 | */ 7 | 8 | function makecol($value,$type = 'text', $name, $serial) { 9 | 10 | /* $string = ''; 15 | return($string);*/ 16 | return makecolumn($value); 17 | } 18 | 19 | function makecolumn($string) 20 | { 21 | return("" . $string . ''); 22 | } 23 | 24 | function makerow($devtype,$controller,$VLAN,$v4mask,$policies, 25 | $desc,$src,$rownum) { 26 | print ""; 27 | print $devtype . $controller . $VLAN . $v4mask . 28 | $policies . $src . $desc ; 29 | print ''; 31 | print ""; 32 | } 33 | 34 | 35 | 36 | 37 | /* 38 | * Read in config 39 | * 40 | */ 41 | 42 | function read_config($file,&$basic,&$mans,&$vlans,&$defaults) { 43 | 44 | if ( ($conf_json=file_get_contents($file)) == FALSE ) { 45 | print "
No config file
\n"; 46 | } 47 | 48 | $top=json_decode($conf_json, $assoc = TRUE); 49 | if ( json_last_error() != JSON_ERROR_NONE ) { 50 | print "JSON error"; 51 | exit; 52 | } 53 | 54 | foreach($top as $key => $value) { 55 | switch($key) { 56 | case "VLANs": 57 | $vlans=$value; 58 | break; 59 | case "Manufacturers": 60 | $mans=$value; 61 | break; 62 | case "DefaultACL": 63 | $defaults=$value; 64 | break; 65 | default: 66 | $basic[$key]=$value; 67 | } 68 | } 69 | 70 | if (! isset($basic['Default_VLAN'] )) { 71 | $basic['Default_VLAN']=''; 72 | $basic['Default_Localv4']=''; 73 | } 74 | } 75 | 76 | function init_database(&$client,&$mud,&$vlan,&$policies) 77 | { 78 | $client = new MongoDB\Client("mongodb://localhost:27017"); 79 | $mud = $client->mud_manager->mudfile; 80 | $vlan = $client->mud_manager->vlans; 81 | $policies = $client->mud_manager->mud_policies; 82 | } 83 | 84 | // return a JSON array of the indices in the array 85 | 86 | function makeindex_json($indices) { 87 | 88 | $res= '[ '; 89 | 90 | for ( $i = 0 ; $i < sizeof($indices) ; $i++ ) { 91 | $res = $res . ' "' . $indices[$i] . '"'; 92 | if ($i < (sizeof($indices) - 1)) { 93 | $res = $res . ', '; 94 | } 95 | } 96 | 97 | $res = $res . ' ]'; 98 | return $res; 99 | } 100 | -------------------------------------------------------------------------------- /webui/index.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /webui/mm.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* take a row element, access the columns, and generate JSON array. 4 | */ 5 | function mkcol(ind,cells) { 6 | 7 | var k='[ '; // start array 8 | var i; 9 | var end = cells.length - 1; // skip checkbox at the end. 10 | 11 | for (i=0; i< end; i++) { 12 | if ( cells[i].firstElementChild != null ) { // input or span 13 | var inp=cells[i].firstElementChild; 14 | 15 | if ( inp.localName == "input" ) { // null for input 16 | k= k + '"' + inp.value + '",'; 17 | } else { // is span 18 | k= k + '"' + inp.innerText + '",'; 19 | } 20 | } else { 21 | k= k + '"' + cells[i].innerText + '",'; // add element in quotes 22 | } 23 | } 24 | k= k + ind + ' ]'; // close array 25 | return k; 26 | } 27 | 28 | 29 | /* make an array of elements that are selected. */ 30 | 31 | function t_to_a(tid,json) { 32 | var i; 33 | var rows=document.getElementById(tid).rows; 34 | var json=document.getElementById(json); 35 | var res='[ '; 36 | var addcomma=''; 37 | for (i=1;i < rows.length; i++) { // skip the header 38 | var last = rows[i].cells.length - 1; 39 | var thecell=rows[i].cells[last].firstElementChild; 40 | if ( thecell.type == 'checkbox' && 41 | thecell.checked == true ) { 42 | if ( addcomma == ',' ) { 43 | res = res + addcomma; 44 | } 45 | res = res + mkcol(i-1,rows[i].cells); 46 | addcomma=','; 47 | } 48 | } 49 | res = res + ' ]'; 50 | json.value = res; 51 | return; 52 | } 53 | 54 | 55 | function isEditable(colnum,source) { 56 | 57 | switch(colnum) { 58 | case 1: 59 | if ( source == 'MUD state') { 60 | return(true); 61 | } else { 62 | return(false); 63 | } 64 | case 2: // VLAN 65 | case 3: 66 | if ( source != 'config file' ) { 67 | return(true); 68 | } 69 | default: 70 | return(false); 71 | } 72 | } 73 | 74 | function toggleEditable(mybutton,idx) { 75 | 76 | if( mybutton.checked == true ) { 77 | makeEditable(mybutton); 78 | } else { 79 | makeUneditable(mybutton); 80 | } 81 | } 82 | 83 | // copy any innerText into the value of an input. Cycle through 84 | // each element in a row and test if editable first. 85 | // find the row of the checkbox that is checked. We'll rely on this 86 | // for this purpose. 87 | 88 | function makeEditable(mybutton) { 89 | var row=mybutton.parentNode.parentNode; 90 | var source=row.cells[5].innerText; 91 | var i; 92 | 93 | // we need the source. this will be in cell 5. 94 | 95 | for (i=0; ifindOneAndUpdate( 19 | [ $qkey => $qvalue ], // query 20 | [ '$set' => [ $ukey => $uvalue ]], /* edit */ 21 | [ 'upsert' => $upsert,/* options */ 22 | 'returnDocument' => 23 | MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER]); 24 | } 25 | catch(MongoResultException $e) { 26 | print "
editDB: " . $qkey . " " . $qvalue . " " . $ukey . 27 | " " . $uvalue . "
";
 28 |         
 29 |         echo $e->getCode(), " : ", $e->getMessage(), "\n";
 30 |         var_dump($e->getDocument());
 31 |         print "
"; 32 | exit; 33 | } 34 | } 35 | 36 | function queryDB($coll,$query,$element) 37 | { 38 | try { 39 | $update=$coll->findOne($query); // query 40 | } 41 | catch(MongoResultException $e) { 42 | print "
queryDB: " . $query . " " . $element . "
";
 43 |         echo $e->getCode(), " : ", $e->getMessage(), "\n";
 44 |         var_dump($e->getDocument());
 45 |         print "
"; 46 | exit; 47 | } 48 | 49 | if (isset($update)) { 50 | return($update[$element]); 51 | } else { 52 | return(null); 53 | } 54 | } 55 | 56 | 57 | function deleteOne($coll,$query) 58 | { 59 | try { 60 | $update=$coll->deleteOne($query); // query 61 | } 62 | catch(MongoResultException $e) { 63 | print "deleteOne: " . $query . "
";
 64 | 
 65 |         echo $e->getCode(), " : ", $e->getMessage(), "\n";
 66 |         var_dump($e->getDocument());
 67 |         print "
"; 68 | exit; 69 | } 70 | } 71 | 72 | function bootserver($list) 73 | { 74 | $json= '{ "Update_URLs" : [ '; 75 | 76 | for ($i=0; $i< sizeof($list); $i++) { 77 | $json = $json . ' "' . $list[$i] . '" '; 78 | if ($i < (sizeof($list) - 1)) { 79 | $json = $json . ', '; 80 | } 81 | } 82 | $json = $json . ' ] }'; 83 | 84 | /* ok, do the curl to the server. */ 85 | $curl= curl_init(); 86 | curl_setopt($curl, CURLOPT_POST, 1); 87 | curl_setopt($curl,CURLOPT_POSTFIELDS, $json); 88 | curl_setopt($curl, CURLOPT_URL, "http://localhost:8000/cfg_change"); 89 | curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1); 90 | $result=curl_exec($curl); 91 | curl_close($curl); 92 | 93 | } 94 | 95 | 96 | 97 | 98 | 99 | /* first read in JSON array. */ 100 | 101 | $json=$_POST["json"]; 102 | 103 | $top=json_decode($json,$assoc=true); 104 | 105 | $k=json_last_error(); 106 | if ( $k != JSON_ERROR_NONE ) { 107 | print "JSON error: " . json_last_error_msg(); 108 | exit; 109 | } 110 | 111 | $indices=json_decode($_POST["indices"]); 112 | 113 | $k=json_last_error(); 114 | 115 | if ( $k != JSON_ERROR_NONE ) { 116 | print "JSON error: " . json_last_error_msg(); 117 | exit; 118 | } 119 | 120 | /* so here's the situation. in the last array entry we have the index 121 | * needed to find the index into the appropriate database collection. 122 | * yeah, that's index->index->entry. Yuck, but that's the web for you. 123 | */ 124 | 125 | $url_idx=0; 126 | 127 | 128 | for ( $i = 0; $i < sizeof($top); $i++) { 129 | $e=$top[$i]; 130 | 131 | // create an associative array of an array of elements for our convenience. 132 | $row= [ 'devtype' => $e[0], 'controller' => $e[1], 133 | 'vlan' => $e[2], 'netmask' => $e[3], 'policies' => $e[4], 134 | 'source' => $e[5], 'desc' => $e[6] , 'index' => $indices[intval($e[7])]]; 135 | $table[$i]=$row; 136 | 137 | } 138 | 139 | init_database($client,$mudfile_collection,$vlan_collection, 140 | $policies_collection); 141 | 142 | for ( $i=0;$i< sizeof($table); $i++) { 143 | $row=$table[$i]; 144 | $rules=$row['source']; 145 | 146 | switch($row['source']) { 147 | case "MUD state": /* here the index points to a URL. 148 | * Update MUD file and policies DB. */ 149 | /* check value of controller. it should be an IP address. 150 | * If not, don't update it. 151 | */ 152 | if ( filter_var($row['controller'],FILTER_VALIDATE_IP) ) { 153 | editDB($mudfile_collection,'URI',$row['index'], 154 | 'Controller',$row['controller'],false); 155 | } 156 | 157 | /* now do the VLAN and netmask in the policies and VLAN databases. 158 | *Treat as a number. */ 159 | 160 | $num=(int) $row['vlan']; 161 | $url=$row['index']; 162 | $url_list[$url_idx++]=$url; 163 | $url_bits=parse_url($url); 164 | $host=$url_bits['host']; 165 | 166 | if ( $num > 0 ) { /* only update vlan if we have one */ 167 | 168 | /* if row exists, update, if it doesn't exist, create it. */ 169 | /* check first against the mud-url. */ 170 | 171 | $oldmask=queryDB($vlan_collection,[ 'VLAN_ID' => $num ], 172 | 'v4addrmask'); 173 | $oldvlan=queryDB($vlan_collection, 174 | [ "Owner" => [ '$in' => [ $url, $host ]] ], 175 | 'VLAN_ID'); 176 | 177 | if ( ($oldvlan == $num) ) { // only update the v4addrmask. 178 | $update=editDB($vlan_collection,"VLAN_ID", $num, 179 | 'v4addrmask',$row['netmask'], false); 180 | } else { 181 | /* We change VLANs- 182 | * We *only* do this per MUD-URL, not per manufacturer. This is 183 | * a bit of a limitation, in that one might want a bulk change. 184 | * For now, too bad. 185 | */ 186 | 187 | /* remove entry from any existing VLAN DB Owner arrays. */ 188 | 189 | 190 | 191 | try { 192 | $update=$vlan_collection->updateMany([], 193 | [ '$pull' => [ "Owner" => $url ] ]); 194 | } 195 | catch(MongoResultException $e) { 196 | echo $e->getCode(), " : ", $e->getMessage(), "\n"; 197 | var_dump($e->getDocument()); 198 | } 199 | 200 | // ok, that cleaned out the cruft. Now we need to do the 201 | // new push. don't do this for the default. That is- 202 | // upsert = false. 203 | 204 | if ( $num != $basic['Default_VLAN'] ){ 205 | 206 | $update=$vlan_collection->findOneAndUpdate( 207 | [ "VLAN_ID" => $num ], 208 | [ '$push' => [ "Owner" => $url ] ], [ 'upsert' => true ]); 209 | /* now update v4addrmask. */ 210 | editDB($vlan_collection, "VLAN_ID", $num, 211 | 'v4addrmask',$row['netmask'],false); 212 | /* whack policies collection with new VLAN_ID */ 213 | } 214 | print "
whacking " . $url . "to be " . $num . "
"; 215 | 216 | try { 217 | $update=$policies_collection->updateMany( 218 | ['URI' => $url], 219 | ['$set' => ["VLAN" => $num]]); 220 | } 221 | catch(MongoResultException $e) { 222 | echo $e->getCode(), " : ", $e->getMessage(), "\n"; 223 | var_dump($e->getDocument()); 224 | } 225 | } 226 | } 227 | 228 | break; 229 | case "VLAN DB": // VLANs join the party here. 230 | $num=(int) $row['vlan']; 231 | $idx=(int) $row['index']; 232 | if ( $num > 0 ) { 233 | editDB($vlan_collection, 'VLAN_ID', $idx, 234 | 'VLAN_ID',$num,false); 235 | editDB($vlan_collection, 'VLAN_ID', $idx, 236 | 'v4addrmask',$row['netmask'],false); 237 | } 238 | } 239 | } 240 | 241 | bootserver($url_list); 242 | 243 | $_SESSION['update']='true'; 244 | 245 | header('Location: mud-home.php'); 246 | 247 | 248 | -------------------------------------------------------------------------------- /webui/mud-home.php: -------------------------------------------------------------------------------- 1 | find(); 46 | 47 | print $table_front; 48 | 49 | foreach ($mud_cursor as $mud_entry) { 50 | $devtype=''; 51 | $controller=''; 52 | $VLAN=''; 53 | $v4mask=''; 54 | $policies=''; 55 | $desc=''; 56 | 57 | /* first cell: Device type */ 58 | $mud_uri=$mud_entry["URI"]; 59 | 60 | $authority=parse_url($mud_uri,PHP_URL_HOST); 61 | 62 | /* do some heuristics for what to put in this collumn */ 63 | 64 | if (isset($mud_entry["Manufacturer-Label"])) { 65 | $c=$mud_entry["Manufacturer-Label"]; 66 | } else { // whack the MUD-URL into an authority 67 | $c=$authority; 68 | } 69 | // next add the model if it exists. 70 | if ( isset($mud_entry["Manufacturer-Model"]) ) { 71 | $c = $c . " " . $mud_entry["Manufacturer-Model"]; 72 | } 73 | $devtype= makecolumn($c); 74 | 75 | /* on to $controller. This must come either from the database or 76 | * config. 77 | */ 78 | 79 | /* always try the db first. */ 80 | 81 | if (isset($mud_entry['Controller'])) { 82 | $controller=$mud_entry['Controller']; 83 | } else { 84 | for ($i=0;$i< sizeof($mans); $i++) { 85 | /* mans uses authority. It's what we have. */ 86 | $e = $mans[$i]; 87 | if ($e["authority"] == $authority) { 88 | if ( isset($e["my_controller_v4"])) { 89 | $controller = $e["my_controller_v4"]; 90 | } 91 | unset($mans[$i]); 92 | } 93 | } 94 | } 95 | 96 | /* wrap $controller in an td input */ 97 | if ( $controller != '') { 98 | $controller = makecol($controller,"text","ctrlr",$serial++); 99 | } else { 100 | if ( isset($mud_entry["Needs-my-controller"]) && 101 | ( $mud_entry["Needs-my-controller"]== "yes" )) { 102 | $controller= 'none available'; 103 | } else { 104 | $controller=""; 105 | } 106 | 107 | $controller=makecolumn($controller); 108 | } 109 | 110 | 111 | // Do VLAN. 112 | 113 | $vlan_array=$vlan_collection->findOne([ "Owner" => 114 | [ '$in' => [ $mud_uri ] ]]); 115 | if ( $vlan_array == NULL ) { 116 | $vlan_array=$vlan_collection->findOne([ "Owner" => 117 | [ '$in' => [ $authority ] ]]); 118 | } 119 | 120 | if ( $vlan_array != NULL ) { 121 | $VLAN=$vlan_array["VLAN_ID"]; 122 | $v4mask=$vlan_array["v4addrmask"]; 123 | $v6mask=$vlan_array["v6addrmask"]; 124 | } else { 125 | // check to see if we have a default. 126 | if ( isset($basic['Default_VLAN'])) { 127 | $VLAN=$basic['Default_VLAN']; 128 | $v4mask=$basic['Default_Localv4']; 129 | $v6mask=$basic['Default_Localv6']; 130 | } 131 | } 132 | 133 | 134 | $VLAN=makecol($VLAN,"number","vlan",$serial++); 135 | $v4mask=makecol($v4mask,"text","v4msk",$serial++); 136 | 137 | // on to policies. There are as many as three sets: 138 | // * the mud file 139 | // * inbound 140 | // * outbound 141 | 142 | // The MUD file will be found in the current mud_entry. We want 143 | // a pointer tho, and so we'll just point to the MUD URL. 144 | 145 | $policies='(mud file) '; 146 | $policies= $policies . '(DACLs)'; 148 | $policies= makecolumn($policies); 149 | if ( isset($mud_entry["Manufacturer-Doc"]) ) { 150 | $docs=' (docs)'; 151 | } else { 152 | $docs=''; 153 | } 154 | $desc= $mud_entry["Systeminfo"] . " " . $docs; 155 | if ( strlen($desc) > 22 ) { 156 | $desc='' . $desc . ''; 157 | } 158 | $desc=makecolumn($desc); 159 | 160 | /* Great! we have a row! */ 161 | $rowsource[$rownum]=makecolumn('MUD state'); 162 | $indices[$rownum]=$mud_uri; 163 | makerow($devtype,$controller,$VLAN,$v4mask, 164 | $policies,$desc,$rowsource[$rownum],$rownum++); 165 | } 166 | 167 | 168 | // Ok, so what remains are manufacturers that are in the config file 169 | // and VLANs that aren't used. Let's tackle manufacturers first. 170 | 171 | for ($i=0; $ifindOne([ "Owner" => 187 | [ '$in' => [ $authority ] ]]); 188 | if ( $ventry != NULL ) { 189 | $VLAN=$ventry["VLAN_ID"]; 190 | $v4mask=$ventry["v4addrmask"]; 191 | $v6mask=$ventry["v6addrmask"]; 192 | 193 | } else { 194 | if ( isset($basic["Default_VLAN"]) ) 195 | { 196 | $VLAN=$basic["Default_VLAN"]; 197 | $v4mask=$basic["Default_Localv4"]; 198 | $v6mask=$basic["Default_Localv6"]; 199 | } 200 | } 201 | $VLAN=makecol($VLAN,"number","manvlan",$serial++); 202 | $v4mask=makecol($v4mask,"text","manmask",$serial++); 203 | 204 | // No policies. static description. 205 | $policies=makecolumn(""); 206 | $desc=makecolumn(""); 207 | 208 | $rowsource[$rownum]=makecolumn("config file"); 209 | $indices[$rownum]= $authority; 210 | makerow($devtype,$controller,$VLAN,$v4mask, 211 | $policies,$desc,$rowsource[$rownum],$rownum++); 212 | } 213 | 214 | // OK. Next check for unassigned VLANs. 215 | 216 | $vlan_cursor=$vlan_collection->find(array('Owner' => array('$size' => 0))); 217 | 218 | // there will be no authority, controller, or policies. 219 | 220 | foreach ( $vlan_cursor as $vlan_entry ) { 221 | $devtype=makecolumn(""); 222 | $controller=makecolumn(''); 223 | $vlannum=$vlan_entry['VLAN_ID']; 224 | $VLAN=makecol($vlan_entry['VLAN_ID'],"number","vl",$serial++); 225 | $v4mask=makecol($vlan_entry['v4addrmask'],"text","vm",$serial++); 226 | // $v6mask=makecol($vlan_entry['v6addrmask'],"text","vm",$serial++); // not quite yet. 227 | $policies=makecolumn(""); 228 | $desc=makecolumn("Unassigned VLAN"); 229 | 230 | $rowsource[$rownum]=makecolumn("VLAN DB"); 231 | $indices[$rownum]=$vlannum; 232 | makerow($devtype,$controller,$VLAN,$v4mask, 233 | $policies,$desc,$rowsource[$rownum],$rownum++); 234 | } 235 | 236 | // ok, build out index json 237 | $index_json = makeindex_json($indices); 238 | 239 | print "

"; 240 | if ( isset($_SESSION['update']) && ($_SESSION['update'] == 'true')) { 241 | $_SESSION['update']='false'; 242 | print 'Database Updated'; 243 | 244 | } 245 | 246 | print '

'; 247 | print '
'; 248 | print ''; 250 | print "

"; 251 | ?> -------------------------------------------------------------------------------- /webui/show-acl-policy.php: -------------------------------------------------------------------------------- 1 | find([ 'URI' => $url ]); 31 | 32 | print $begin; 33 | print "

Policies for devices with MUDURL " . $url . ":

"; 34 | 35 | 36 | 37 | foreach ( $policies as $policy ) { 38 | 39 | print "
";
40 |     $p_array=iterator_to_array($policy);
41 |     
42 |     foreach ( array_keys($p_array) as $key) {
43 |         switch ( $key ) {
44 |         case "_id":
45 |             break;
46 |         case "DACL":
47 |             $p_array[$key]=str_replace("," , ",\n\t" ,$p_array[$key]);
48 |         default:
49 |             print $key . ": " . $p_array[$key] . "\n";
50 |         }
51 |     }
52 |     print "

"; 53 | } 54 | -------------------------------------------------------------------------------- /webui/statics.php: -------------------------------------------------------------------------------- 1 | 5 | MUD Manager Configuration 6 | 7 | 8 | 9 | 10 | 11 |

MUD Manager Configuration

12 |

This is the MUD Manager Configuration Screen. Click "edit" on those 13 | rows you wish to change.

14 | 15 | BEGIN; 16 | 17 | $table_front=<<< TABLEFRONT 18 |
19 | 21 | 22 | TABLEFRONT; 23 | 24 | $pbegin=<<< PBEGIN 25 | 26 | Policies 27 | 28 | 29 | 30 | PBEGIN; 31 | -------------------------------------------------------------------------------- /webui/style.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | width: 80%; 4 | margin-right: 70px; 5 | margin-left: 70px; 6 | margin-top: 40px; 7 | } 8 | 9 | table, td { 10 | border: 1px solid #aaa; 11 | } 12 | 13 | th { 14 | border: 1px solid #aaa; 15 | background-color: #176264; 16 | color: white; 17 | } 18 | 19 | tr:nth-child(even) { 20 | background-color: #dddddd; 21 | } 22 | 23 | body { 24 | font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; 25 | } 26 | 27 | p { 28 | margin-right: 70px; 29 | margin-left: 70px; 30 | } 31 | 32 | input[type="number"] { 33 | width:60px; 34 | } 35 | --------------------------------------------------------------------------------
Device TypeControllerVLANNet MaskPoliciesSourceDescriptionEdit?