All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_soh.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 60a153e2e33ef5d3edaf2bedcd672c9c3b2a0a61 $
19  * @file rlm_soh.c
20  * @brief Decodes Microsoft's Statement of Health sub-protocol.
21  *
22  * @copyright 2010 Phil Mayers <p.mayers@imperial.ac.uk>
23  */
24 RCSID("$Id: 60a153e2e33ef5d3edaf2bedcd672c9c3b2a0a61 $")
25 
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/dhcp.h>
29 #include <freeradius-devel/soh.h>
30 
31 
32 typedef struct rlm_soh_t {
33  char const *xlat_name;
34  bool dhcp;
35 } rlm_soh_t;
36 
37 
38 /*
39  * Not sure how to make this useful yet...
40  */
41 static ssize_t soh_xlat(char **out, size_t outlen,
42  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
43  REQUEST *request, char const *fmt)
44 {
45  VALUE_PAIR* vp[6];
46  char const *osname;
47 
48  /*
49  * There will be no point unless SoH-Supported = yes
50  */
51  vp[0] = fr_pair_find_by_num(request->packet->vps, 0, PW_SOH_SUPPORTED, TAG_ANY);
52  if (!vp[0])
53  return 0;
54 
55 
56  if (strncasecmp(fmt, "OS", 2) == 0) {
57  /* OS vendor */
58  vp[0] = fr_pair_find_by_num(request->packet->vps, 0, PW_SOH_MS_MACHINE_OS_VENDOR, TAG_ANY);
59  vp[1] = fr_pair_find_by_num(request->packet->vps, 0, PW_SOH_MS_MACHINE_OS_VERSION, TAG_ANY);
60  vp[2] = fr_pair_find_by_num(request->packet->vps, 0, PW_SOH_MS_MACHINE_OS_RELEASE, TAG_ANY);
61  vp[3] = fr_pair_find_by_num(request->packet->vps, 0, PW_SOH_MS_MACHINE_OS_BUILD, TAG_ANY);
62  vp[4] = fr_pair_find_by_num(request->packet->vps, 0, PW_SOH_MS_MACHINE_SP_VERSION, TAG_ANY);
63  vp[5] = fr_pair_find_by_num(request->packet->vps, 0, PW_SOH_MS_MACHINE_SP_RELEASE, TAG_ANY);
64 
65  if (vp[0] && vp[0]->vp_integer == VENDORPEC_MICROSOFT) {
66  if (!vp[1]) {
67  snprintf(*out, outlen, "Windows unknown");
68  } else {
69  switch (vp[1]->vp_integer) {
70  case 7:
71  osname = "7";
72  break;
73 
74  case 6:
75  osname = "Vista";
76  break;
77 
78  case 5:
79  osname = "XP";
80  break;
81 
82  default:
83  osname = "Other";
84  break;
85  }
86  snprintf(*out, outlen, "Windows %s %d.%d.%d sp %d.%d", osname, vp[1]->vp_integer,
87  vp[2] ? vp[2]->vp_integer : 0,
88  vp[3] ? vp[3]->vp_integer : 0,
89  vp[4] ? vp[4]->vp_integer : 0,
90  vp[5] ? vp[5]->vp_integer : 0);
91  }
92  return strlen(*out);
93  }
94  }
95 
96  return 0;
97 }
98 
99 
100 static const CONF_PARSER module_config[] = {
101  /*
102  * Do SoH over DHCP?
103  */
104  { FR_CONF_OFFSET("dhcp", PW_TYPE_BOOLEAN, rlm_soh_t, dhcp), .dflt = "no" },
106 };
107 
108 
109 static int mod_bootstrap(CONF_SECTION *conf, void *instance)
110 {
111  char const *name;
112  rlm_soh_t *inst = instance;
113 
114  name = cf_section_name2(conf);
115  if (!name) name = cf_section_name1(conf);
116  inst->xlat_name = name;
117  if (!inst->xlat_name) return -1;
118 
119  xlat_register(inst, inst->xlat_name, soh_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
120 
121  return 0;
122 }
123 
124 static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
125 {
126 #ifdef WITH_DHCP
127  int rcode;
128  VALUE_PAIR *vp;
129  rlm_soh_t *inst = instance;
130 
131  if (!inst->dhcp) return RLM_MODULE_NOOP;
132 
133  vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 43, TAG_ANY);
134  if (vp) {
135  /*
136  * vendor-specific options contain
137  *
138  * vendor opt 220/0xdc - SoH payload, or null byte to probe, or string
139  * "NAP" to indicate server-side support for SoH in OFFERs
140  *
141  * vendor opt 222/0xde - SoH correlation ID as utf-16 string, yuck...
142  */
143  uint8_t vopt, vlen;
144  uint8_t const *data;
145 
146  data = vp->vp_octets;
147  while (data < vp->vp_octets + vp->vp_length) {
148  vopt = *data++;
149  vlen = *data++;
150  switch (vopt) {
151  case 220:
152  if (vlen <= 1) {
153  uint8_t *p;
154 
155  RDEBUG("SoH adding NAP marker to DHCP reply");
156  /* client probe; send "NAP" in the reply */
157  vp = fr_pair_afrom_num(request->reply, DHCP_MAGIC_VENDOR, 43);
158  p = talloc_array(vp, uint8_t, 5);
159  p[0] = 220;
160  p[1] = 3;
161  p[4] = 'N';
162  p[3] = 'A';
163  p[2] = 'P';
164  fr_pair_value_memsteal(vp, p);
165  fr_pair_add(&request->reply->vps, vp);
166 
167  } else {
168  RDEBUG("SoH decoding NAP from DHCP request");
169  /* SoH payload */
170  rcode = soh_verify(request, data, vlen);
171  if (rcode < 0) {
172  return RLM_MODULE_FAIL;
173  }
174  }
175  break;
176 
177  default:
178  /* nothing to do */
179  break;
180  }
181  data += vlen;
182  }
183  return RLM_MODULE_OK;
184  }
185 #endif
186  return RLM_MODULE_NOOP;
187 }
188 
189 static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void * instance, REQUEST *request)
190 {
191  VALUE_PAIR *vp;
192  int rv;
193 
194  /* try to find the MS-SoH payload */
195  vp = fr_pair_find_by_num(request->packet->vps, VENDORPEC_MICROSOFT, 55, TAG_ANY);
196  if (!vp) {
197  RDEBUG("SoH radius VP not found");
198  return RLM_MODULE_NOOP;
199  }
200 
201  RDEBUG("SoH radius VP found");
202  /* decode it */
203  rv = soh_verify(request, vp->vp_octets, vp->vp_length);
204  if (rv < 0) {
205  return RLM_MODULE_FAIL;
206  }
207 
208  return RLM_MODULE_OK;
209 }
210 
211 extern module_t rlm_soh;
212 module_t rlm_soh = {
214  .name = "soh",
215  .type = RLM_TYPE_THREAD_SAFE,
216  .inst_size = sizeof(rlm_soh_t),
217  .config = module_config,
218  .bootstrap = mod_bootstrap,
219  .methods = {
222  },
223 };
static int mod_bootstrap(CONF_SECTION *conf, void *instance)
Definition: rlm_soh.c:109
bool dhcp
Definition: rlm_soh.c:34
int xlat_register(void *mod_inst, char const *name, xlat_func_t func, xlat_escape_t escape, xlat_instantiate_t instantiate, size_t inst_size, size_t buf_len)
Register an xlat function.
Definition: xlat.c:717
The module is OK, continue.
Definition: radiusd.h:91
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull)
Metadata exported by the module.
Definition: modules.h:134
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
7 methods index for postauth section.
Definition: modules.h:48
static char const * name
#define vp_octets
Definition: pair.h:170
#define vp_integer
Definition: pair.h:166
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
Handle authorization requests using Couchbase document data.
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: modules.h:75
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
static ssize_t soh_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_soh.c:41
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
#define inst
struct rlm_soh_t rlm_soh_t
#define XLAT_DEFAULT_BUF_LEN
Definition: xlat.h:89
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
#define VENDORPEC_MICROSOFT
Definition: radius.h:200
static const CONF_PARSER module_config[]
Definition: rlm_soh.c:100
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
A truth value.
Definition: radius.h:56
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
static rs_t * conf
Definition: radsniff.c:46
char const * cf_section_name1(CONF_SECTION const *cs)
Definition: conffile.c:3592
Module succeeded without doing anything.
Definition: radiusd.h:96
static rlm_rcode_t CC_HINT(nonnull)
Definition: rlm_soh.c:124
uint8_t data[]
Definition: eap_pwd.h:625
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
Module failed, don't reply.
Definition: radiusd.h:90
void fr_pair_value_memsteal(VALUE_PAIR *vp, uint8_t const *src)
Reparent an allocated octet buffer to a VALUE_PAIR.
Definition: pair.c:1933
#define TAG_ANY
Definition: pair.h:191
int soh_verify(REQUEST *request, uint8_t const *data, unsigned int data_len) CC_HINT(nonnull)
Parse the MS-SOH response in data and update sohvp.
Definition: soh.c:385
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
char const * xlat_name
Definition: rlm_soh.c:33
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:43
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
module_t rlm_soh
Definition: rlm_soh.c:212
#define DHCP_MAGIC_VENDOR
Definition: dhcp.h:97
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
1 methods index for authorize section.
Definition: modules.h:42
#define RCSID(id)
Definition: build.h:135
#define RDEBUG(fmt,...)
Definition: log.h:243
char const * cf_section_name2(CONF_SECTION const *cs)
Definition: conffile.c:3601