/src/net-snmp/snmplib/snmpusm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Portions of this file are subject to the following copyright(s). See |
2 | | * the Net-SNMP's COPYING file for more details and other copyrights |
3 | | * that may apply: |
4 | | */ |
5 | | /* |
6 | | * Portions of this file are copyrighted by: |
7 | | * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. |
8 | | * Use is subject to license terms specified in the COPYING file |
9 | | * distributed with the Net-SNMP package. |
10 | | * |
11 | | * Portions of this file are copyrighted by: |
12 | | * Copyright (c) 2016 VMware, Inc. All rights reserved. |
13 | | * Use is subject to license terms specified in the COPYING file |
14 | | * distributed with the Net-SNMP package. |
15 | | */ |
16 | | /* |
17 | | * snmpusm.c |
18 | | * |
19 | | * Routines to manipulate a information about a "user" as |
20 | | * defined by the SNMP-USER-BASED-SM-MIB MIB. |
21 | | * |
22 | | * All functions usm_set_usmStateReference_*() return 0 on success, -1 |
23 | | * otherwise. |
24 | | * |
25 | | * !! Tab stops set to 4 in some parts of this file. !! |
26 | | * (Designated on a per function.) |
27 | | */ |
28 | | |
29 | | #include <net-snmp/net-snmp-config.h> |
30 | | #include <net-snmp/net-snmp-features.h> |
31 | | |
32 | | #include <sys/types.h> |
33 | | #include <stdio.h> |
34 | | #ifdef HAVE_STDLIB_H |
35 | | #include <stdlib.h> |
36 | | #endif |
37 | | #ifdef TIME_WITH_SYS_TIME |
38 | | # include <sys/time.h> |
39 | | # include <time.h> |
40 | | #else |
41 | | # ifdef HAVE_SYS_TIME_H |
42 | | # include <sys/time.h> |
43 | | # else |
44 | | # include <time.h> |
45 | | # endif |
46 | | #endif |
47 | | #ifdef HAVE_STRING_H |
48 | | #include <string.h> |
49 | | #else |
50 | | #include <strings.h> |
51 | | #endif |
52 | | #ifdef HAVE_NETINET_IN_H |
53 | | #include <netinet/in.h> |
54 | | #endif |
55 | | |
56 | | #ifdef HAVE_UNISTD_H |
57 | | #include <unistd.h> |
58 | | #endif |
59 | | |
60 | | #include <net-snmp/types.h> |
61 | | #include <net-snmp/output_api.h> |
62 | | #include <net-snmp/config_api.h> |
63 | | #include <net-snmp/utilities.h> |
64 | | |
65 | | #include <net-snmp/library/asn1.h> |
66 | | #include <net-snmp/library/snmp_api.h> |
67 | | #include <net-snmp/library/callback.h> |
68 | | #include <net-snmp/library/tools.h> |
69 | | #include <net-snmp/library/keytools.h> |
70 | | #include <net-snmp/library/snmpv3.h> |
71 | | #include <net-snmp/library/lcd_time.h> |
72 | | #include <net-snmp/library/scapi.h> |
73 | | #include <net-snmp/library/callback.h> |
74 | | #include <net-snmp/library/snmp_secmod.h> |
75 | | #include <net-snmp/library/snmpusm.h> |
76 | | #include <net-snmp/library/transform_oids.h> |
77 | | #include <net-snmp/library/snmp_enum.h> |
78 | | |
79 | | #ifdef HAVE_OPENSSL_DH_H |
80 | | #include <openssl/dh.h> |
81 | | #endif |
82 | | |
83 | | netsnmp_feature_child_of(usm_all, libnetsnmp); |
84 | | netsnmp_feature_child_of(usm_support, usm_all); |
85 | | |
86 | | netsnmp_feature_require(usm_support); |
87 | | |
88 | | struct usmStateReference { |
89 | | int refcnt; |
90 | | char *usr_name; |
91 | | size_t usr_name_length; |
92 | | u_char *usr_engine_id; |
93 | | size_t usr_engine_id_length; |
94 | | oid *usr_auth_protocol; |
95 | | size_t usr_auth_protocol_length; |
96 | | u_char *usr_auth_key; |
97 | | size_t usr_auth_key_length; |
98 | | oid *usr_priv_protocol; |
99 | | size_t usr_priv_protocol_length; |
100 | | u_char *usr_priv_key; |
101 | | size_t usr_priv_key_length; |
102 | | u_int usr_sec_level; |
103 | | }; |
104 | | |
105 | | const oid usmNoAuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID, |
106 | | NETSNMP_USMAUTH_NOAUTH }; |
107 | | #ifndef NETSNMP_DISABLE_MD5 |
108 | | const oid usmHMACMD5AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID, |
109 | | NETSNMP_USMAUTH_HMACMD5 }; |
110 | | #endif |
111 | | const oid usmHMACSHA1AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID, |
112 | | NETSNMP_USMAUTH_HMACSHA1 }; |
113 | | |
114 | | #ifdef HAVE_EVP_SHA384 |
115 | | const oid usmHMAC384SHA512AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID, |
116 | | NETSNMP_USMAUTH_HMAC384SHA512 }; |
117 | | const oid usmHMAC256SHA384AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID, |
118 | | NETSNMP_USMAUTH_HMAC256SHA384 }; |
119 | | #endif /* HAVE_EVP_SHA384 */ |
120 | | |
121 | | #ifdef HAVE_EVP_SHA224 |
122 | | const oid usmHMAC192SHA256AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID, |
123 | | NETSNMP_USMAUTH_HMAC192SHA256 }; |
124 | | const oid usmHMAC128SHA224AuthProtocol[10] = { NETSNMP_USMAUTH_BASE_OID, |
125 | | NETSNMP_USMAUTH_HMAC128SHA224 }; |
126 | | #endif /* HAVE_EVP_SHA384 */ |
127 | | |
128 | | const oid usmNoPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 }; |
129 | | |
130 | | #ifndef NETSNMP_DISABLE_DES |
131 | | const oid usmDESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 }; |
132 | | #endif |
133 | | |
134 | | |
135 | | const oid usmAESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 4 }; |
136 | | /* backwards compat */ |
137 | | const oid *usmAES128PrivProtocol = usmAESPrivProtocol; |
138 | | |
139 | | #ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04 |
140 | | /* OIDs from http://www.snmp.com/eso/esoConsortiumMIB.txt */ |
141 | | const oid usmAES192PrivProtocol[9] = { 1,3,6,1,4,1,14832,1,3 }; |
142 | | const oid usmAES256PrivProtocol[9] = { 1,3,6,1,4,1,14832,1,4 }; |
143 | | /* OIDs from CISCO MIB */ |
144 | | const oid usmAES192CiscoPrivProtocol[11] = { 1,3,6,1,4,1,9,12,6,1,1 }; |
145 | | const oid usmAES256CiscoPrivProtocol[11] = { 1,3,6,1,4,1,9,12,6,1,2 }; |
146 | | /* |
147 | | * these OIDs are in pySNMP source as OIDs for AES+Reeder. We'll just |
148 | | * use OIDS from CISCO-SNMP-USM-OIDS-MIB |
149 | | * |
150 | | const oid usmAES192Cisco2PrivProtocol[11] = { 1,3,6,1,4,1,9,12,6,1,101 }; |
151 | | const oid usmAES256Cisco2PrivProtocol[11] = { 1,3,6,1,4,1,9,12,6,1,102 }; |
152 | | */ |
153 | | #endif /* NETSNMP_DRAFT_BLUMENTHAL_AES_04 */ |
154 | | |
155 | | typedef struct usm_alg_type_s { |
156 | | const char *label; |
157 | | int value; |
158 | | } usm_alg_type_t; |
159 | | |
160 | | static const usm_alg_type_t usm_auth_type[] = { |
161 | | { "NOAUTH", NETSNMP_USMAUTH_NOAUTH }, |
162 | | { "SHA", NETSNMP_USMAUTH_HMACSHA1 }, |
163 | | { "SHA-1", NETSNMP_USMAUTH_HMACSHA1 }, |
164 | | { "SHA1", NETSNMP_USMAUTH_HMACSHA1 }, |
165 | | #ifndef NETSNMP_DISABLE_MD5 |
166 | | { "MD5", NETSNMP_USMAUTH_HMACMD5 }, |
167 | | #endif |
168 | | #ifdef HAVE_EVP_SHA224 |
169 | | { "SHA-224", NETSNMP_USMAUTH_HMAC128SHA224 }, |
170 | | { "SHA224", NETSNMP_USMAUTH_HMAC128SHA224 }, |
171 | | { "SHA-256", NETSNMP_USMAUTH_HMAC192SHA256 }, |
172 | | { "SHA256", NETSNMP_USMAUTH_HMAC192SHA256 }, |
173 | | #endif |
174 | | #ifdef HAVE_EVP_SHA384 |
175 | | { "SHA-384", NETSNMP_USMAUTH_HMAC256SHA384 }, |
176 | | { "SHA384", NETSNMP_USMAUTH_HMAC256SHA384 }, |
177 | | { "SHA-512", NETSNMP_USMAUTH_HMAC384SHA512 }, |
178 | | { "SHA512", NETSNMP_USMAUTH_HMAC384SHA512 }, |
179 | | #endif |
180 | | { NULL, -1 } |
181 | | }; |
182 | | |
183 | | static const usm_alg_type_t usm_priv_type[] = { |
184 | | { "NOPRIV", USM_CREATE_USER_PRIV_NONE }, |
185 | | #ifndef NETSNMP_DISABLE_DES |
186 | | { "DES", USM_CREATE_USER_PRIV_DES }, |
187 | | #endif |
188 | | #ifdef HAVE_AES |
189 | | { "AES", USM_CREATE_USER_PRIV_AES }, |
190 | | { "AES-128", USM_CREATE_USER_PRIV_AES }, |
191 | | { "AES128", USM_CREATE_USER_PRIV_AES }, |
192 | | #ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04 |
193 | | { "AES-192", USM_CREATE_USER_PRIV_AES192 }, |
194 | | { "AES192", USM_CREATE_USER_PRIV_AES192 }, |
195 | | { "AES-256", USM_CREATE_USER_PRIV_AES256 }, |
196 | | { "AES256", USM_CREATE_USER_PRIV_AES256 }, |
197 | | /** cisco / pysnmp variations */ |
198 | | { "AES-192-C", USM_CREATE_USER_PRIV_AES192_CISCO }, |
199 | | { "AES192C", USM_CREATE_USER_PRIV_AES192_CISCO }, |
200 | | { "AES-256-C", USM_CREATE_USER_PRIV_AES256_CISCO }, |
201 | | { "AES256C", USM_CREATE_USER_PRIV_AES256_CISCO }, |
202 | | #endif |
203 | | #endif |
204 | | { NULL, -1 }, |
205 | | }; |
206 | | |
207 | | static u_int dummy_etime, dummy_eboot; /* For ISENGINEKNOWN(). */ |
208 | | |
209 | | /* |
210 | | * Set up default snmpv3 parameter value storage. |
211 | | */ |
212 | | #ifdef NETSNMP_SECMOD_USM |
213 | | static const oid *defaultAuthType = NULL; |
214 | | static size_t defaultAuthTypeLen = 0; |
215 | | static const oid *defaultPrivType = NULL; |
216 | | static size_t defaultPrivTypeLen = 0; |
217 | | #endif /* NETSNMP_SECMOD_USM */ |
218 | | |
219 | | /* |
220 | | * Globals. |
221 | | */ |
222 | | static u_int salt_integer; |
223 | | #ifdef HAVE_AES |
224 | | static u_int salt_integer64_1, salt_integer64_2; |
225 | | #endif |
226 | | /* |
227 | | * 1/2 of seed for the salt. Cf. RFC2274, Sect 8.1.1.1. |
228 | | */ |
229 | | |
230 | | static struct usmUser *noNameUser = NULL; |
231 | | /* |
232 | | * Local storage (LCD) of the default user list. |
233 | | */ |
234 | | static struct usmUser *userList = NULL; |
235 | | |
236 | | /* |
237 | | * Set a given field of the secStateRef. |
238 | | * |
239 | | * Allocate <len> bytes for type <type> pointed to by ref-><field>. |
240 | | * Then copy in <item> and record its length in ref-><field_len>. |
241 | | * |
242 | | * Return 0 on success, -1 otherwise. |
243 | | */ |
244 | 0 | #define MAKE_ENTRY(ref, type, item, len, field, field_len) \ |
245 | 0 | do { \ |
246 | 0 | if (ref == NULL) \ |
247 | 0 | return -1; \ |
248 | 0 | if (ref->field != NULL) { \ |
249 | 0 | SNMP_ZERO(ref->field, ref->field_len); \ |
250 | 0 | SNMP_FREE(ref->field); \ |
251 | 0 | } \ |
252 | 0 | ref->field_len = 0; \ |
253 | 0 | if (len == 0 || item == NULL) \ |
254 | 0 | return 0; \ |
255 | 0 | ref->field = netsnmp_memdup(item, len * sizeof(type)); \ |
256 | 0 | if (ref->field == NULL) \ |
257 | 0 | return -1; \ |
258 | 0 | \ |
259 | 0 | ref->field_len = len; \ |
260 | 0 | return 0; \ |
261 | 0 | } while (0) |
262 | | |
263 | | static int |
264 | | usm_clone_usmStateReference(struct usmStateReference *from, |
265 | | struct usmStateReference **to); |
266 | | |
267 | | static int |
268 | | free_enginetime_on_shutdown(int majorid, int minorid, void *serverarg, |
269 | | void *clientarg) |
270 | 0 | { |
271 | 0 | u_char engineID[SNMP_MAX_ENG_SIZE]; |
272 | 0 | size_t engineID_len = sizeof(engineID); |
273 | |
|
274 | 0 | DEBUGMSGTL(("snmpv3", "free enginetime callback called\n")); |
275 | |
|
276 | 0 | engineID_len = snmpv3_get_engineID(engineID, engineID_len); |
277 | 0 | if (engineID_len > 0) |
278 | 0 | free_enginetime(engineID, engineID_len); |
279 | 0 | return 0; |
280 | 0 | } |
281 | | |
282 | | static struct usmStateReference * |
283 | | usm_malloc_usmStateReference(void) |
284 | 0 | { |
285 | 0 | struct usmStateReference *retval; |
286 | |
|
287 | 0 | retval = calloc(1, sizeof(struct usmStateReference)); |
288 | 0 | if (retval) |
289 | 0 | retval->refcnt = 1; |
290 | |
|
291 | 0 | return retval; |
292 | 0 | } /* end usm_malloc_usmStateReference() */ |
293 | | |
294 | | static int |
295 | | usm_clone(netsnmp_pdu *pdu, netsnmp_pdu *new_pdu) |
296 | 0 | { |
297 | 0 | struct usmStateReference *ref = pdu->securityStateRef; |
298 | 0 | struct usmStateReference **new_ref = |
299 | 0 | (struct usmStateReference **)&new_pdu->securityStateRef; |
300 | 0 | int ret = 0; |
301 | |
|
302 | 0 | if (!ref) |
303 | 0 | return ret; |
304 | | |
305 | 0 | if (pdu->command == SNMP_MSG_TRAP2) { |
306 | 0 | netsnmp_assert(pdu->securityModel == SNMP_DEFAULT_SECMODEL); |
307 | 0 | ret = usm_clone_usmStateReference(ref, new_ref); |
308 | 0 | } else { |
309 | 0 | netsnmp_assert(ref == *new_ref); |
310 | 0 | ref->refcnt++; |
311 | 0 | } |
312 | |
|
313 | 0 | return ret; |
314 | 0 | } |
315 | | |
316 | | static void |
317 | | usm_free_usmStateReference(void *old) |
318 | 0 | { |
319 | 0 | struct usmStateReference *ref = old; |
320 | |
|
321 | 0 | if (!ref) |
322 | 0 | return; |
323 | | |
324 | 0 | if (--ref->refcnt > 0) |
325 | 0 | return; |
326 | | |
327 | 0 | SNMP_FREE(ref->usr_name); |
328 | 0 | SNMP_FREE(ref->usr_engine_id); |
329 | 0 | SNMP_FREE(ref->usr_auth_protocol); |
330 | 0 | SNMP_FREE(ref->usr_priv_protocol); |
331 | |
|
332 | 0 | if (ref->usr_auth_key_length && ref->usr_auth_key) { |
333 | 0 | SNMP_ZERO(ref->usr_auth_key, ref->usr_auth_key_length); |
334 | 0 | SNMP_FREE(ref->usr_auth_key); |
335 | 0 | } |
336 | 0 | if (ref->usr_priv_key_length && ref->usr_priv_key) { |
337 | 0 | SNMP_ZERO(ref->usr_priv_key, ref->usr_priv_key_length); |
338 | 0 | SNMP_FREE(ref->usr_priv_key); |
339 | 0 | } |
340 | |
|
341 | 0 | SNMP_FREE(ref); |
342 | 0 | } /* end usm_free_usmStateReference() */ |
343 | | |
344 | | struct usmUser * |
345 | | usm_get_userList(void) |
346 | 0 | { |
347 | 0 | return userList; |
348 | 0 | } |
349 | | |
350 | | static int |
351 | | usm_set_usmStateReference_name(struct usmStateReference *ref, |
352 | | char *name, size_t name_len) |
353 | 0 | { |
354 | 0 | MAKE_ENTRY(ref, char, name, name_len, usr_name, usr_name_length); |
355 | 0 | } |
356 | | |
357 | | static int |
358 | | usm_set_usmStateReference_engine_id(struct usmStateReference *ref, |
359 | | u_char * engine_id, |
360 | | size_t engine_id_len) |
361 | 0 | { |
362 | 0 | MAKE_ENTRY(ref, u_char, engine_id, engine_id_len, |
363 | 0 | usr_engine_id, usr_engine_id_length); |
364 | 0 | } |
365 | | |
366 | | static int |
367 | | usm_set_usmStateReference_auth_protocol(struct usmStateReference *ref, |
368 | | oid * auth_protocol, |
369 | | size_t auth_protocol_len) |
370 | 0 | { |
371 | 0 | MAKE_ENTRY(ref, oid, auth_protocol, auth_protocol_len, |
372 | 0 | usr_auth_protocol, usr_auth_protocol_length); |
373 | 0 | } |
374 | | |
375 | | static int |
376 | | usm_set_usmStateReference_auth_key(struct usmStateReference *ref, |
377 | | u_char * auth_key, size_t auth_key_len) |
378 | 0 | { |
379 | 0 | MAKE_ENTRY(ref, u_char, auth_key, auth_key_len, |
380 | 0 | usr_auth_key, usr_auth_key_length); |
381 | 0 | } |
382 | | |
383 | | static int |
384 | | usm_set_usmStateReference_priv_protocol(struct usmStateReference *ref, |
385 | | oid * priv_protocol, |
386 | | size_t priv_protocol_len) |
387 | 0 | { |
388 | 0 | MAKE_ENTRY(ref, oid, priv_protocol, priv_protocol_len, |
389 | 0 | usr_priv_protocol, usr_priv_protocol_length); |
390 | 0 | } |
391 | | |
392 | | static int |
393 | | usm_set_usmStateReference_priv_key(struct usmStateReference *ref, |
394 | | u_char * priv_key, size_t priv_key_len) |
395 | 0 | { |
396 | 0 | MAKE_ENTRY(ref, u_char, priv_key, priv_key_len, |
397 | 0 | usr_priv_key, usr_priv_key_length); |
398 | 0 | } |
399 | | |
400 | | static int |
401 | | usm_set_usmStateReference_sec_level(struct usmStateReference *ref, |
402 | | int sec_level) |
403 | 0 | { |
404 | 0 | if (ref == NULL) |
405 | 0 | return -1; |
406 | 0 | ref->usr_sec_level = sec_level; |
407 | 0 | return 0; |
408 | 0 | } |
409 | | |
410 | | static int |
411 | | usm_clone_usmStateReference(struct usmStateReference *from, |
412 | | struct usmStateReference **to) |
413 | 0 | { |
414 | 0 | struct usmStateReference *cloned_usmStateRef; |
415 | |
|
416 | 0 | if (from == NULL || to == NULL) |
417 | 0 | return -1; |
418 | | |
419 | 0 | *to = usm_malloc_usmStateReference(); |
420 | 0 | cloned_usmStateRef = *to; |
421 | |
|
422 | 0 | if (usm_set_usmStateReference_name(cloned_usmStateRef, from->usr_name, from->usr_name_length) || |
423 | 0 | usm_set_usmStateReference_engine_id(cloned_usmStateRef, from->usr_engine_id, from->usr_engine_id_length) || |
424 | 0 | usm_set_usmStateReference_auth_protocol(cloned_usmStateRef, from->usr_auth_protocol, from->usr_auth_protocol_length) || |
425 | 0 | usm_set_usmStateReference_auth_key(cloned_usmStateRef, from->usr_auth_key, from->usr_auth_key_length) || |
426 | 0 | usm_set_usmStateReference_priv_protocol(cloned_usmStateRef, from->usr_priv_protocol, from->usr_priv_protocol_length) || |
427 | 0 | usm_set_usmStateReference_priv_key(cloned_usmStateRef, from->usr_priv_key, from->usr_priv_key_length) || |
428 | 0 | usm_set_usmStateReference_sec_level(cloned_usmStateRef, from->usr_sec_level)) |
429 | 0 | { |
430 | 0 | usm_free_usmStateReference(*to); |
431 | 0 | *to = NULL; |
432 | 0 | return -1; |
433 | 0 | } |
434 | | |
435 | 0 | return 0; |
436 | |
|
437 | 0 | } |
438 | | |
439 | | #ifdef NETSNMP_ENABLE_TESTING_CODE |
440 | | /*******************************************************************-o-****** |
441 | | * emergency_print |
442 | | * |
443 | | * Parameters: |
444 | | * *field |
445 | | * length |
446 | | * |
447 | | * This is a print routine that is solely included so that it can be |
448 | | * used in gdb. Don't use it as a function, it will be pulled before |
449 | | * a real release of the code. |
450 | | * |
451 | | * tab stop 4 |
452 | | * |
453 | | * XXX fflush() only works on FreeBSD; core dumps on Sun OS's |
454 | | */ |
455 | | void |
456 | | emergency_print(u_char * field, u_int length) |
457 | | { |
458 | | int iindex; |
459 | | int start = 0; |
460 | | int stop = 25; |
461 | | |
462 | | while (start < stop) { |
463 | | for (iindex = start; iindex < stop; iindex++) |
464 | | printf("%02X ", field[iindex]); |
465 | | |
466 | | printf("\n"); |
467 | | start = stop; |
468 | | stop = stop + 25 < length ? stop + 25 : length; |
469 | | } |
470 | | fflush(0); |
471 | | |
472 | | } /* end emergency_print() */ |
473 | | #endif /* NETSNMP_ENABLE_TESTING_CODE */ |
474 | | |
475 | | static struct usmUser * |
476 | | usm_get_user_from_list(const u_char *engineID, size_t engineIDLen, |
477 | | const char *name, size_t nameLen, |
478 | | struct usmUser *puserList, int use_default) |
479 | 0 | { |
480 | 0 | struct usmUser *ptr; |
481 | |
|
482 | 0 | for (ptr = puserList; ptr != NULL; ptr = ptr->next) { |
483 | 0 | if (ptr->name && strlen(ptr->name) == nameLen && |
484 | 0 | memcmp(ptr->name, name, nameLen) == 0) { |
485 | 0 | DEBUGMSGTL(("usm", "match on user %s\n", ptr->name)); |
486 | 0 | if (ptr->engineIDLen == engineIDLen && |
487 | 0 | ((ptr->engineID == NULL && engineID == NULL) || |
488 | 0 | (ptr->engineID != NULL && engineID != NULL && |
489 | 0 | memcmp(ptr->engineID, engineID, engineIDLen) == 0))) |
490 | 0 | return ptr; |
491 | 0 | DEBUGMSGTL(("usm", "no match on engineID (")); |
492 | 0 | if (engineID) { |
493 | 0 | DEBUGMSGHEX(("usm", engineID, engineIDLen)); |
494 | 0 | } else { |
495 | 0 | DEBUGMSGTL(("usm", "Empty EngineID")); |
496 | 0 | } |
497 | 0 | DEBUGMSG(("usm", ")\n")); |
498 | 0 | } |
499 | 0 | } |
500 | | |
501 | | /* |
502 | | * return "" user used to facilitate engineID discovery |
503 | | */ |
504 | 0 | if (use_default && !strcmp(name, "")) |
505 | 0 | return noNameUser; |
506 | 0 | return NULL; |
507 | 0 | } |
508 | | |
509 | | struct usmUser * |
510 | | usm_get_user2(const u_char *engineID, size_t engineIDLen, const void *name, |
511 | | size_t nameLen) |
512 | 0 | { |
513 | 0 | DEBUGMSGTL(("usm", "getting user %.*s\n", (int)nameLen, |
514 | 0 | (const char *)name)); |
515 | 0 | return usm_get_user_from_list(engineID, engineIDLen, name, nameLen, |
516 | 0 | userList, 1); |
517 | 0 | } |
518 | | |
519 | | /* |
520 | | * usm_get_user(): Returns a user from userList based on the engineID, |
521 | | * engineIDLen and name of the requested user. |
522 | | */ |
523 | | struct usmUser * |
524 | | usm_get_user(const u_char *engineID, size_t engineIDLen, const char *name) |
525 | 0 | { |
526 | 0 | return usm_get_user2(engineID, engineIDLen, name, strlen(name)); |
527 | 0 | } |
528 | | |
529 | | static struct usmUser * |
530 | | usm_add_user_to_list(struct usmUser *user, struct usmUser *puserList) |
531 | 0 | { |
532 | 0 | struct usmUser *nptr, *pptr, *optr; |
533 | | |
534 | | /* |
535 | | * loop through puserList till we find the proper, sorted place to |
536 | | * insert the new user |
537 | | */ |
538 | | /* XXX - how to handle a NULL user->name ?? */ |
539 | | /* XXX - similarly for a NULL nptr->name ?? */ |
540 | 0 | for (nptr = puserList, pptr = NULL; nptr != NULL; |
541 | 0 | pptr = nptr, nptr = nptr->next) { |
542 | 0 | if (nptr->engineIDLen > user->engineIDLen) |
543 | 0 | break; |
544 | | |
545 | 0 | if (user->engineID == NULL && nptr->engineID != NULL) |
546 | 0 | break; |
547 | | |
548 | 0 | if (nptr->engineIDLen == user->engineIDLen && |
549 | 0 | (nptr->engineID != NULL && user->engineID != NULL && |
550 | 0 | memcmp(nptr->engineID, user->engineID, |
551 | 0 | user->engineIDLen) > 0)) |
552 | 0 | break; |
553 | | |
554 | 0 | if (!(nptr->engineID == NULL && user->engineID != NULL)) { |
555 | 0 | if (nptr->engineIDLen == user->engineIDLen && |
556 | 0 | ((nptr->engineID == NULL && user->engineID == NULL) || |
557 | 0 | memcmp(nptr->engineID, user->engineID, |
558 | 0 | user->engineIDLen) == 0) |
559 | 0 | && strlen(nptr->name) > strlen(user->name)) |
560 | 0 | break; |
561 | | |
562 | 0 | if (nptr->engineIDLen == user->engineIDLen && |
563 | 0 | ((nptr->engineID == NULL && user->engineID == NULL) || |
564 | 0 | memcmp(nptr->engineID, user->engineID, |
565 | 0 | user->engineIDLen) == 0) |
566 | 0 | && strlen(nptr->name) == strlen(user->name) |
567 | 0 | && strcmp(nptr->name, user->name) > 0) |
568 | 0 | break; |
569 | | |
570 | 0 | if (nptr->engineIDLen == user->engineIDLen && |
571 | 0 | ((nptr->engineID == NULL && user->engineID == NULL) || |
572 | 0 | memcmp(nptr->engineID, user->engineID, |
573 | 0 | user->engineIDLen) == 0) |
574 | 0 | && strlen(nptr->name) == strlen(user->name) |
575 | 0 | && strcmp(nptr->name, user->name) == 0) { |
576 | | /* |
577 | | * the user is an exact match of a previous entry. |
578 | | * Credentials may be different, though, so remove |
579 | | * the old entry (and add the new one)! |
580 | | */ |
581 | 0 | if (pptr) { /* change prev's next pointer */ |
582 | 0 | pptr->next = nptr->next; |
583 | 0 | } |
584 | 0 | if (nptr->next) { /* change next's prev pointer */ |
585 | 0 | nptr->next->prev = pptr; |
586 | 0 | } |
587 | 0 | optr = nptr; |
588 | 0 | nptr = optr->next; /* add new user at this position */ |
589 | | /* free the old user */ |
590 | 0 | optr->next=NULL; |
591 | 0 | optr->prev=NULL; |
592 | 0 | usm_free_user(optr); |
593 | 0 | break; /* new user will be added below */ |
594 | 0 | } |
595 | 0 | } |
596 | 0 | } |
597 | | |
598 | | /* |
599 | | * nptr should now point to the user that we need to add ourselves |
600 | | * in front of, and pptr should be our new 'prev'. |
601 | | */ |
602 | | |
603 | | /* |
604 | | * change our pointers |
605 | | */ |
606 | 0 | user->prev = pptr; |
607 | 0 | user->next = nptr; |
608 | | |
609 | | /* |
610 | | * change the next's prev pointer |
611 | | */ |
612 | 0 | if (user->next) |
613 | 0 | user->next->prev = user; |
614 | | |
615 | | /* |
616 | | * change the prev's next pointer |
617 | | */ |
618 | 0 | if (user->prev) |
619 | 0 | user->prev->next = user; |
620 | | |
621 | | /* |
622 | | * rewind to the head of the list and return it (since the new head |
623 | | * could be us, we need to notify the above routine who the head now is. |
624 | | */ |
625 | 0 | for (pptr = user; pptr->prev != NULL; pptr = pptr->prev); |
626 | 0 | return pptr; |
627 | 0 | } |
628 | | |
629 | | /* |
630 | | * usm_add_user(): Add's a user to the userList, sorted by the |
631 | | * engineIDLength then the engineID then the name length then the name |
632 | | * to facilitate getNext calls on a usmUser table which is indexed by |
633 | | * these values. |
634 | | * |
635 | | * returns the head of the list (which could change due to this add). |
636 | | */ |
637 | | |
638 | | struct usmUser * |
639 | | usm_add_user(struct usmUser *user) |
640 | 0 | { |
641 | 0 | struct usmUser *uptr; |
642 | 0 | uptr = usm_add_user_to_list(user, userList); |
643 | 0 | if (uptr != NULL) |
644 | 0 | userList = uptr; |
645 | 0 | return uptr; |
646 | 0 | } |
647 | | |
648 | | /* |
649 | | * usm_remove_usmUser_from_list remove user from (optional) list |
650 | | * |
651 | | * if list is not specified, defaults to global userList. |
652 | | * |
653 | | * returns SNMPERR_SUCCESS or SNMPERR_USM_UNKNOWNSECURITYNAME |
654 | | */ |
655 | | static int |
656 | | usm_remove_usmUser_from_list(struct usmUser *user, struct usmUser **ppuserList) |
657 | 0 | { |
658 | 0 | struct usmUser *nptr, *pptr; |
659 | | |
660 | | /* |
661 | | * NULL pointers aren't allowed |
662 | | */ |
663 | 0 | if (ppuserList == NULL) |
664 | 0 | ppuserList = &userList; |
665 | |
|
666 | 0 | if (*ppuserList == NULL) |
667 | 0 | return SNMPERR_USM_UNKNOWNSECURITYNAME; |
668 | | |
669 | | /* |
670 | | * find the user in the list |
671 | | */ |
672 | 0 | for (nptr = *ppuserList, pptr = NULL; nptr != NULL; |
673 | 0 | pptr = nptr, nptr = nptr->next) { |
674 | 0 | if (nptr == user) |
675 | 0 | break; |
676 | 0 | } |
677 | |
|
678 | 0 | if (nptr) { |
679 | | /* |
680 | | * remove the user from the linked list |
681 | | */ |
682 | 0 | if (pptr) { |
683 | 0 | pptr->next = nptr->next; |
684 | 0 | } |
685 | 0 | if (nptr->next) { |
686 | 0 | nptr->next->prev = pptr; |
687 | 0 | } |
688 | 0 | } else { |
689 | | /* |
690 | | * user didn't exist |
691 | | */ |
692 | 0 | return SNMPERR_USM_UNKNOWNSECURITYNAME; |
693 | 0 | } |
694 | 0 | if (nptr == *ppuserList) /* we're the head of the list, need to change |
695 | | * * the head to the next user */ |
696 | 0 | *ppuserList = nptr->next; |
697 | 0 | return SNMPERR_SUCCESS; |
698 | 0 | } /* end usm_remove_usmUser_from_list() */ |
699 | | |
700 | | /* |
701 | | * usm_remove_user_from_list |
702 | | * |
703 | | * removes user from list. |
704 | | * |
705 | | * returns new list head on success, or NULL on error. |
706 | | * |
707 | | * NOTE: if there was only one user in the list, list head will be NULL. |
708 | | * So NULL can also mean success. Use the newer usm_remove_usmUser() for |
709 | | * more specific return codes. This function is kept for backwards |
710 | | * compatability with this ambiguous behaviour. |
711 | | */ |
712 | | static struct usmUser * |
713 | | usm_remove_user_from_list(struct usmUser *user, |
714 | | struct usmUser **ppuserList) |
715 | 0 | { |
716 | 0 | int rc = usm_remove_usmUser_from_list(user, ppuserList); |
717 | 0 | if (rc != SNMPERR_SUCCESS || NULL == ppuserList) |
718 | 0 | return NULL; |
719 | | |
720 | 0 | return *ppuserList; |
721 | 0 | } /* end usm_remove_user_from_list() */ |
722 | | |
723 | | /* |
724 | | * usm_remove_user(): finds and removes a user from a list |
725 | | */ |
726 | | struct usmUser * |
727 | | usm_remove_user(struct usmUser *user) |
728 | 0 | { |
729 | 0 | return usm_remove_user_from_list(user, &userList); |
730 | 0 | } |
731 | | |
732 | | /* |
733 | | * usm_free_user(): calls free() on all needed parts of struct usmUser and |
734 | | * the user himself. |
735 | | * |
736 | | * Note: This should *not* be called on an object in a list (IE, |
737 | | * remove it from the list first, and set next and prev to NULL), but |
738 | | * will try to reconnect the list pieces again if it is called this |
739 | | * way. If called on the head of the list, the entire list will be |
740 | | * lost. |
741 | | */ |
742 | | struct usmUser * |
743 | | usm_free_user(struct usmUser *user) |
744 | 0 | { |
745 | 0 | if (user == NULL) |
746 | 0 | return NULL; |
747 | | |
748 | 0 | SNMP_FREE(user->engineID); |
749 | 0 | SNMP_FREE(user->name); |
750 | 0 | SNMP_FREE(user->secName); |
751 | 0 | SNMP_FREE(user->cloneFrom); |
752 | 0 | SNMP_FREE(user->userPublicString); |
753 | 0 | SNMP_FREE(user->authProtocol); |
754 | 0 | SNMP_FREE(user->privProtocol); |
755 | |
|
756 | 0 | if (user->authKey != NULL) { |
757 | 0 | SNMP_ZERO(user->authKey, user->authKeyLen); |
758 | 0 | SNMP_FREE(user->authKey); |
759 | 0 | } |
760 | |
|
761 | 0 | if (user->privKey != NULL) { |
762 | 0 | SNMP_ZERO(user->privKey, user->privKeyLen); |
763 | 0 | SNMP_FREE(user->privKey); |
764 | 0 | } |
765 | |
|
766 | 0 | if (user->authKeyKu != NULL) { |
767 | 0 | SNMP_ZERO(user->authKeyKu, user->authKeyKuLen); |
768 | 0 | SNMP_FREE(user->authKeyKu); |
769 | 0 | } |
770 | |
|
771 | 0 | if (user->privKeyKu != NULL) { |
772 | 0 | SNMP_ZERO(user->privKeyKu, user->privKeyKuLen); |
773 | 0 | SNMP_FREE(user->privKeyKu); |
774 | 0 | } |
775 | |
|
776 | 0 | #ifdef NETSNMP_USE_OPENSSL |
777 | 0 | if (user->usmDHUserAuthKeyChange) |
778 | 0 | { |
779 | 0 | DH_free(user->usmDHUserAuthKeyChange); |
780 | 0 | user->usmDHUserAuthKeyChange = NULL; |
781 | 0 | } |
782 | |
|
783 | 0 | if (user->usmDHUserPrivKeyChange) |
784 | 0 | { |
785 | 0 | DH_free(user->usmDHUserPrivKeyChange); |
786 | 0 | user->usmDHUserPrivKeyChange = NULL; |
787 | 0 | } |
788 | 0 | #endif |
789 | | |
790 | | /* |
791 | | * FIX Why not put this check *first?* |
792 | | */ |
793 | 0 | if (user->prev != NULL && user->prev != (struct usmUser *)-1) { /* ack, this shouldn't happen */ |
794 | 0 | user->prev->next = user->next; |
795 | 0 | } |
796 | 0 | if (user->next != NULL && user->next != (struct usmUser *)-1) { |
797 | 0 | user->next->prev = user->prev; |
798 | 0 | if (user->prev != NULL) /* ack this is really bad, because it means |
799 | | * * we'll loose the head of some structure tree */ |
800 | 0 | DEBUGMSGTL(("usm", |
801 | 0 | "Severe: Asked to free the head of a usmUser tree somewhere.")); |
802 | 0 | } |
803 | | |
804 | |
|
805 | 0 | SNMP_ZERO(user, sizeof(*user)); |
806 | 0 | SNMP_FREE(user); |
807 | |
|
808 | 0 | return NULL; /* for convenience to returns from calling functions */ |
809 | |
|
810 | 0 | } /* end usm_free_user() */ |
811 | | |
812 | | int usm_set_priv_key(struct usmUser *user, const char *fname, |
813 | | u_char **old_key, size_t *old_key_len, |
814 | | const u_char *new_key, u_int new_key_len) |
815 | 0 | { |
816 | 0 | u_char buf[SNMP_MAXBUF_SMALL], buf2[SNMP_MAXBUF_SMALL]; |
817 | 0 | size_t buflen = sizeof(buf); |
818 | 0 | int plen, res; |
819 | |
|
820 | 0 | plen = sc_get_proper_priv_length(user->privProtocol, |
821 | 0 | user->privProtocolLen); |
822 | 0 | DEBUGMSGTL(("usmUser", "plen %d\n", plen)); |
823 | | /* |
824 | | * extend key as needed |
825 | | */ |
826 | 0 | DEBUGMSGTL(("9:usmUser", "%s: new_key_len %d\n", fname, new_key_len)); |
827 | 0 | if (new_key_len < 2 * plen) { |
828 | 0 | struct usmUser dummy; |
829 | |
|
830 | 0 | memset(&dummy, 0x0, sizeof(dummy)); |
831 | 0 | dummy.engineID = user->engineID; |
832 | 0 | dummy.engineIDLen = user->engineIDLen; |
833 | 0 | dummy.authProtocol = user->authProtocol; |
834 | 0 | dummy.authProtocolLen = user->authProtocolLen; |
835 | 0 | dummy.privProtocol = user->privProtocol; |
836 | 0 | dummy.privProtocolLen = user->privProtocolLen; |
837 | 0 | memcpy(buf2, new_key, new_key_len); |
838 | 0 | dummy.privKey = buf2; |
839 | 0 | dummy.privKeyLen = new_key_len; |
840 | 0 | res = usm_extend_user_kul(&dummy, sizeof(buf2)); |
841 | 0 | if (res != SNMP_ERR_NOERROR) { |
842 | 0 | DEBUGMSGTL(("usmUser", "%s: extend kul failed\n", fname)); |
843 | 0 | return SNMP_ERR_GENERR; |
844 | 0 | } |
845 | 0 | DEBUGMSGTL(("9:usmUser", "%s: extend kul OK\n", fname)); |
846 | 0 | new_key = dummy.privKey; |
847 | 0 | new_key_len = dummy.privKeyLen; |
848 | | /* |
849 | | * make sure no reallocation happened; buf2 must be large enoungh |
850 | | */ |
851 | 0 | netsnmp_assert(dummy.privKey == buf2); |
852 | 0 | } |
853 | | |
854 | | /* |
855 | | * Change the key. |
856 | | */ |
857 | 0 | DEBUGMSGTL(("usmUser", "%s: changing priv key for user %s\n", |
858 | 0 | fname, user->secName)); |
859 | |
|
860 | 0 | res = decode_keychange(user->authProtocol, user->authProtocolLen, |
861 | 0 | user->privKey, user->privKeyLen, new_key, |
862 | 0 | new_key_len, buf, &buflen); |
863 | 0 | if (res != SNMPERR_SUCCESS) { |
864 | 0 | DEBUGMSGTL(("usmUser", "%s failed\n", fname)); |
865 | 0 | return SNMP_ERR_GENERR; |
866 | 0 | } |
867 | 0 | DEBUGMSGTL(("usmUser", "%s succeeded\n", fname)); |
868 | 0 | *old_key = user->privKey; |
869 | 0 | *old_key_len = user->privKeyLen; |
870 | 0 | user->privKey = netsnmp_memdup(buf, buflen); |
871 | 0 | if (user->privKey == NULL) |
872 | 0 | return SNMP_ERR_RESOURCEUNAVAILABLE; |
873 | 0 | user->privKeyLen = buflen; |
874 | 0 | return SNMP_ERR_NOERROR; |
875 | 0 | } |
876 | | |
877 | | /*******************************************************************-o-****** |
878 | | * usm_generate_OID |
879 | | * |
880 | | * Parameters: |
881 | | * *prefix (I) OID prefix to the usmUser table entry. |
882 | | * prefixLen (I) |
883 | | * *uptr (I) Pointer to a user in the user list. |
884 | | * *length (O) Length of generated index OID. |
885 | | * |
886 | | * Returns: |
887 | | * Pointer to the OID index for the user (uptr) -OR- |
888 | | * NULL on failure. |
889 | | * |
890 | | * |
891 | | * Generate the index OID for a given usmUser name. 'length' is set to |
892 | | * the length of the index OID. |
893 | | * |
894 | | * Index OID format is: |
895 | | * |
896 | | * <...prefix>.<engineID_length>.<engineID>.<user_name_length>.<user_name> |
897 | | */ |
898 | | oid * |
899 | | usm_generate_OID(const oid *prefix, size_t prefixLen, |
900 | | const struct usmUser *uptr, size_t *length) |
901 | 0 | { |
902 | 0 | oid *indexOid; |
903 | 0 | int i; |
904 | |
|
905 | 0 | *length = 2 + uptr->engineIDLen + strlen(uptr->name) + prefixLen; |
906 | 0 | indexOid = malloc(*length * sizeof(oid)); |
907 | 0 | if (!indexOid) |
908 | 0 | return indexOid; |
909 | | |
910 | 0 | memmove(indexOid, prefix, prefixLen * sizeof(oid)); |
911 | |
|
912 | 0 | indexOid[prefixLen] = uptr->engineIDLen; |
913 | 0 | for (i = 0; i < uptr->engineIDLen; i++) |
914 | 0 | indexOid[prefixLen + 1 + i] = (oid) uptr->engineID[i]; |
915 | |
|
916 | 0 | indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name); |
917 | 0 | for (i = 0; i < strlen(uptr->name); i++) |
918 | 0 | indexOid[prefixLen + uptr->engineIDLen + 2 + i] = (oid) uptr->name[i]; |
919 | |
|
920 | 0 | return indexOid; |
921 | 0 | } /* end usm_generate_OID() */ |
922 | | |
923 | | /*******************************************************************-o-****** |
924 | | * asn_predict_int_length |
925 | | * |
926 | | * Parameters: |
927 | | * type (UNUSED) |
928 | | * number |
929 | | * len |
930 | | * |
931 | | * Returns: |
932 | | * Number of bytes necessary to store the ASN.1 encoded value of 'number'. |
933 | | * |
934 | | * |
935 | | * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will |
936 | | * use to encode a particular integer value. |
937 | | * |
938 | | * Returns the length of the integer -- NOT THE HEADER! |
939 | | * |
940 | | * Do this the same way as asn_build_int()... |
941 | | */ |
942 | | static int |
943 | | asn_predict_int_length(int type, long number, size_t len) |
944 | 0 | { |
945 | 0 | register u_long mask; |
946 | | |
947 | |
|
948 | 0 | if (len != sizeof(long)) |
949 | 0 | return -1; |
950 | | |
951 | 0 | mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1); |
952 | | /* |
953 | | * mask is 0xFF800000 on a big-endian machine |
954 | | */ |
955 | |
|
956 | 0 | while ((((number & mask) == 0) || ((number & mask) == mask)) |
957 | 0 | && len > 1) { |
958 | 0 | len--; |
959 | 0 | number <<= 8; |
960 | 0 | } |
961 | |
|
962 | 0 | return len; |
963 | |
|
964 | 0 | } /* end asn_predict_length() */ |
965 | | |
966 | | /*******************************************************************-o-****** |
967 | | * asn_predict_length |
968 | | * |
969 | | * Parameters: |
970 | | * type |
971 | | * *ptr |
972 | | * u_char_len |
973 | | * |
974 | | * Returns: |
975 | | * Length in bytes: 1 + <n> + <u_char_len>, where |
976 | | * |
977 | | * 1 For the ASN.1 type. |
978 | | * <n> # of bytes to store length of data. |
979 | | * <u_char_len> Length of data associated with ASN.1 type. |
980 | | * |
981 | | * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will |
982 | | * use to encode a particular integer value. This is as broken as the |
983 | | * currently used encoder. |
984 | | * |
985 | | * XXX How is <n> chosen, exactly?? |
986 | | */ |
987 | | static int |
988 | | asn_predict_length(int type, u_char * ptr, size_t u_char_len) |
989 | 0 | { |
990 | |
|
991 | 0 | if (type & ASN_SEQUENCE) |
992 | 0 | return 1 + 3 + u_char_len; |
993 | | |
994 | 0 | if (type & ASN_INTEGER) { |
995 | 0 | u_long value; |
996 | 0 | memcpy(&value, ptr, u_char_len); |
997 | 0 | u_char_len = asn_predict_int_length(type, value, u_char_len); |
998 | 0 | } |
999 | |
|
1000 | 0 | if (u_char_len < 0x80) |
1001 | 0 | return 1 + 1 + u_char_len; |
1002 | 0 | else if (u_char_len < 0xFF) |
1003 | 0 | return 1 + 2 + u_char_len; |
1004 | 0 | else |
1005 | 0 | return 1 + 3 + u_char_len; |
1006 | |
|
1007 | 0 | } /* end asn_predict_length() */ |
1008 | | |
1009 | | /*******************************************************************-o-****** |
1010 | | * usm_calc_offsets |
1011 | | * |
1012 | | * Parameters: |
1013 | | * (See list below...) |
1014 | | * |
1015 | | * Returns: |
1016 | | * 0 On success, |
1017 | | * -1 Otherwise. |
1018 | | * |
1019 | | * |
1020 | | * This routine calculates the offsets into an outgoing message buffer |
1021 | | * for the necessary values. The outgoing buffer will generically |
1022 | | * look like this: |
1023 | | * |
1024 | | * SNMPv3 Message |
1025 | | * SEQ len[11] |
1026 | | * INT len version |
1027 | | * Header |
1028 | | * SEQ len |
1029 | | * INT len MsgID |
1030 | | * INT len msgMaxSize |
1031 | | * OST len msgFlags (OST = OCTET STRING) |
1032 | | * INT len msgSecurityModel |
1033 | | * MsgSecurityParameters |
1034 | | * [1] OST len[2] |
1035 | | * SEQ len[3] |
1036 | | * OST len msgAuthoritativeEngineID |
1037 | | * INT len msgAuthoritativeEngineBoots |
1038 | | * INT len msgAuthoritativeEngineTime |
1039 | | * OST len msgUserName |
1040 | | * OST len[4] [5] msgAuthenticationParameters |
1041 | | * OST len[6] [7] msgPrivacyParameters |
1042 | | * MsgData |
1043 | | * [8] OST len[9] [10] encryptedPDU |
1044 | | * or |
1045 | | * [8,10] SEQUENCE len[9] scopedPDU |
1046 | | * [12] |
1047 | | * |
1048 | | * The bracketed points will be needed to be identified ([x] is an index |
1049 | | * value, len[x] means a length value). Here is a semantic guide to them: |
1050 | | * |
1051 | | * [1] = globalDataLen (input) |
1052 | | * [2] = otstlen |
1053 | | * [3] = seq_len |
1054 | | * [4] = msgAuthParmLen (may be 0 or 12) |
1055 | | * [5] = authParamsOffset |
1056 | | * [6] = msgPrivParmLen (may be 0 or 8) |
1057 | | * [7] = privParamsOffset |
1058 | | * [8] = globalDataLen + msgSecParmLen |
1059 | | * [9] = datalen |
1060 | | * [10] = dataOffset |
1061 | | * [11] = theTotalLength - the length of the header itself |
1062 | | * [12] = theTotalLength |
1063 | | */ |
1064 | | static int |
1065 | | usm_calc_offsets(size_t globalDataLen, /* SNMPv3Message + HeaderData */ |
1066 | | int secLevel, size_t secEngineIDLen, size_t secNameLen, size_t scopedPduLen, /* An BER encoded sequence. */ |
1067 | | u_long engineboots, /* XXX (asn1.c works in long, not int.) */ |
1068 | | long engine_time, /* XXX (asn1.c works in long, not int.) */ |
1069 | | size_t * theTotalLength, /* globalDataLen + msgSecurityP. + msgData */ |
1070 | | size_t * authParamsOffset, /* Distance to auth bytes. */ |
1071 | | size_t * privParamsOffset, /* Distance to priv bytes. */ |
1072 | | size_t * dataOffset, /* Distance to scopedPdu SEQ -or- the |
1073 | | * crypted (data) portion of msgData. */ |
1074 | | size_t * datalen, /* Size of msgData OCTET STRING encoding. */ |
1075 | | size_t * msgAuthParmLen, /* Size of msgAuthenticationParameters. */ |
1076 | | size_t * msgPrivParmLen, /* Size of msgPrivacyParameters. */ |
1077 | | size_t * otstlen, /* Size of msgSecurityP. O.S. encoding. */ |
1078 | | size_t * seq_len, /* Size of msgSecurityP. SEQ data. */ |
1079 | | size_t * msgSecParmLen) |
1080 | 0 | { /* Size of msgSecurityP. SEQ. */ |
1081 | 0 | int engIDlen, /* Sizes of OCTET STRING and SEQ encodings */ |
1082 | 0 | engBtlen, /* for fields within */ |
1083 | 0 | engTmlen, /* msgSecurityParameters portion of */ |
1084 | 0 | namelen, /* SNMPv3Message. */ |
1085 | 0 | authlen, privlen, ret; |
1086 | | |
1087 | | /* |
1088 | | * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0. |
1089 | | * If doing encryption, msgPrivParmLen = 8 else msgPrivParmLen = 0. |
1090 | | */ |
1091 | 0 | *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV |
1092 | 0 | || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 12 : 0; |
1093 | |
|
1094 | 0 | *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 8 : 0; |
1095 | | |
1096 | | |
1097 | | /* |
1098 | | * Calculate lengths. |
1099 | | */ |
1100 | 0 | if ((engIDlen = asn_predict_length(ASN_OCTET_STR, |
1101 | 0 | NULL, secEngineIDLen)) == -1) { |
1102 | 0 | return -1; |
1103 | 0 | } |
1104 | | |
1105 | 0 | if ((engBtlen = asn_predict_length(ASN_INTEGER, |
1106 | 0 | (u_char *) & engineboots, |
1107 | 0 | sizeof(long))) == -1) { |
1108 | 0 | return -1; |
1109 | 0 | } |
1110 | | |
1111 | 0 | if ((engTmlen = asn_predict_length(ASN_INTEGER, |
1112 | 0 | (u_char *) & engine_time, |
1113 | 0 | sizeof(long))) == -1) { |
1114 | 0 | return -1; |
1115 | 0 | } |
1116 | | |
1117 | 0 | if ((namelen = asn_predict_length(ASN_OCTET_STR, |
1118 | 0 | NULL, secNameLen)) == -1) { |
1119 | 0 | return -1; |
1120 | 0 | } |
1121 | | |
1122 | 0 | if ((authlen = asn_predict_length(ASN_OCTET_STR, |
1123 | 0 | NULL, *msgAuthParmLen)) == -1) { |
1124 | 0 | return -1; |
1125 | 0 | } |
1126 | | |
1127 | 0 | if ((privlen = asn_predict_length(ASN_OCTET_STR, |
1128 | 0 | NULL, *msgPrivParmLen)) == -1) { |
1129 | 0 | return -1; |
1130 | 0 | } |
1131 | | |
1132 | 0 | *seq_len = |
1133 | 0 | engIDlen + engBtlen + engTmlen + namelen + authlen + privlen; |
1134 | |
|
1135 | 0 | if ((ret = asn_predict_length(ASN_SEQUENCE, |
1136 | 0 | NULL, *seq_len)) == -1) { |
1137 | 0 | return -1; |
1138 | 0 | } |
1139 | 0 | *otstlen = (size_t)ret; |
1140 | |
|
1141 | 0 | if ((ret = asn_predict_length(ASN_OCTET_STR, |
1142 | 0 | NULL, *otstlen)) == -1) { |
1143 | 0 | return -1; |
1144 | 0 | } |
1145 | 0 | *msgSecParmLen = (size_t)ret; |
1146 | |
|
1147 | 0 | *authParamsOffset = globalDataLen + +(*msgSecParmLen - *seq_len) |
1148 | 0 | + engIDlen + engBtlen + engTmlen + namelen |
1149 | 0 | + (authlen - *msgAuthParmLen); |
1150 | |
|
1151 | 0 | *privParamsOffset = *authParamsOffset + *msgAuthParmLen |
1152 | 0 | + (privlen - *msgPrivParmLen); |
1153 | | |
1154 | | |
1155 | | /* |
1156 | | * Compute the size of the plaintext. Round up to account for cipher |
1157 | | * block size, if necessary. |
1158 | | * |
1159 | | * XXX This is hardwired for 1DES... If scopedPduLen is already |
1160 | | * a multiple of 8, then *add* 8 more; otherwise, round up |
1161 | | * to the next multiple of 8. |
1162 | | * |
1163 | | * FIX Calculation of encrypted portion of msgData and consequent |
1164 | | * setting and sanity checking of theTotalLength, et al. should |
1165 | | * occur *after* encryption has taken place. |
1166 | | */ |
1167 | 0 | if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
1168 | 0 | scopedPduLen = ROUNDUP8(scopedPduLen); |
1169 | |
|
1170 | 0 | if ((ret = asn_predict_length(ASN_OCTET_STR, NULL, scopedPduLen)) == -1) { |
1171 | 0 | return -1; |
1172 | 0 | } |
1173 | 0 | *datalen = (size_t)ret; |
1174 | 0 | } else { |
1175 | 0 | *datalen = scopedPduLen; |
1176 | 0 | } |
1177 | | |
1178 | 0 | *dataOffset = globalDataLen + *msgSecParmLen + |
1179 | 0 | (*datalen - scopedPduLen); |
1180 | 0 | *theTotalLength = globalDataLen + *msgSecParmLen + *datalen; |
1181 | |
|
1182 | 0 | return 0; |
1183 | |
|
1184 | 0 | } /* end usm_calc_offsets() */ |
1185 | | |
1186 | | #ifndef NETSNMP_DISABLE_DES |
1187 | | /*******************************************************************-o-****** |
1188 | | * usm_set_salt |
1189 | | * |
1190 | | * Parameters: |
1191 | | * *iv (O) Buffer to contain IV. |
1192 | | * *iv_length (O) Length of iv. |
1193 | | * *priv_salt (I) Salt portion of private key. |
1194 | | * priv_salt_length (I) Length of priv_salt. |
1195 | | * *msgSalt (I/O) Pointer salt portion of outgoing msg buffer. |
1196 | | * |
1197 | | * Returns: |
1198 | | * 0 On success, |
1199 | | * -1 Otherwise. |
1200 | | * |
1201 | | * Determine the initialization vector for the DES-CBC encryption. |
1202 | | * (Cf. RFC 2274, 8.1.1.1.) |
1203 | | * |
1204 | | * iv is defined as the concatenation of engineBoots and the |
1205 | | * salt integer. |
1206 | | * The salt integer is incremented. |
1207 | | * The resulting salt is copied into the msgSalt buffer. |
1208 | | * The result of the concatenation is then XORed with the salt |
1209 | | * portion of the private key (last 8 bytes). |
1210 | | * The IV result is returned individually for further use. |
1211 | | */ |
1212 | | static int |
1213 | | usm_set_salt(u_char * iv, |
1214 | | size_t * iv_length, |
1215 | | u_char * priv_salt, size_t priv_salt_length, u_char * msgSalt) |
1216 | 0 | { |
1217 | 0 | size_t propersize_salt = BYTESIZE(USM_DES_SALT_LENGTH); |
1218 | 0 | int net_boots; |
1219 | 0 | int net_salt_int; |
1220 | | /* |
1221 | | * net_* should be encoded in network byte order. XXX Why? |
1222 | | */ |
1223 | 0 | int iindex; |
1224 | | |
1225 | | |
1226 | | /* |
1227 | | * Sanity check. |
1228 | | */ |
1229 | 0 | if (!iv || !iv_length || !priv_salt || (*iv_length != propersize_salt) |
1230 | 0 | || (priv_salt_length < propersize_salt)) { |
1231 | 0 | return -1; |
1232 | 0 | } |
1233 | | |
1234 | | |
1235 | 0 | net_boots = htonl(snmpv3_local_snmpEngineBoots()); |
1236 | 0 | net_salt_int = htonl(salt_integer); |
1237 | |
|
1238 | 0 | salt_integer += 1; |
1239 | |
|
1240 | 0 | memcpy(iv, &net_boots, propersize_salt / 2); |
1241 | 0 | memcpy(iv + (propersize_salt / 2), &net_salt_int, propersize_salt / 2); |
1242 | |
|
1243 | 0 | if (msgSalt) |
1244 | 0 | memcpy(msgSalt, iv, propersize_salt); |
1245 | | |
1246 | | |
1247 | | /* |
1248 | | * Turn the salt into an IV: XOR <boots, salt_int> with salt |
1249 | | * portion of priv_key. |
1250 | | */ |
1251 | 0 | for (iindex = 0; iindex < (int) propersize_salt; iindex++) |
1252 | 0 | iv[iindex] ^= priv_salt[iindex]; |
1253 | | |
1254 | |
|
1255 | 0 | return 0; |
1256 | |
|
1257 | 0 | } /* end usm_set_salt() */ |
1258 | | #endif |
1259 | | |
1260 | | #ifdef HAVE_AES |
1261 | | /*******************************************************************-o-****** |
1262 | | * usm_set_aes_iv |
1263 | | * |
1264 | | * Parameters: |
1265 | | * *iv (O) Buffer to contain IV. |
1266 | | * *iv_length (O) Length of iv. |
1267 | | * net_boots (I) the network byte order of the authEng boots val |
1268 | | * net_time (I) the network byte order of the authEng time val |
1269 | | * *salt (O) A buffer for the outgoing salt (= 8 bytes of iv) |
1270 | | * |
1271 | | * Returns: |
1272 | | * 0 On success, |
1273 | | * -1 Otherwise. |
1274 | | * |
1275 | | * Determine the initialization vector for AES encryption. |
1276 | | * (draft-blumenthal-aes-usm-03.txt, 3.1.2.2) |
1277 | | * |
1278 | | * iv is defined as the concatenation of engineBoots, engineTime |
1279 | | and a 64 bit salt-integer. |
1280 | | * The 64 bit salt integer is incremented. |
1281 | | * The resulting salt is copied into the salt buffer. |
1282 | | * The IV result is returned individually for further use. |
1283 | | */ |
1284 | | static int |
1285 | | usm_set_aes_iv(u_char * iv, |
1286 | | size_t * iv_length, |
1287 | | u_int net_boots, |
1288 | | u_int net_time, |
1289 | | u_char * salt) |
1290 | 0 | { |
1291 | | /* |
1292 | | * net_* should be encoded in network byte order. |
1293 | | */ |
1294 | 0 | int net_salt_int1, net_salt_int2; |
1295 | 0 | #define PROPER_AES_IV_SIZE 64 |
1296 | | |
1297 | | /* |
1298 | | * Sanity check. |
1299 | | */ |
1300 | 0 | if (!iv || !iv_length) { |
1301 | 0 | return -1; |
1302 | 0 | } |
1303 | | |
1304 | 0 | net_salt_int1 = htonl(salt_integer64_1); |
1305 | 0 | net_salt_int2 = htonl(salt_integer64_2); |
1306 | |
|
1307 | 0 | if ((salt_integer64_2 += 1) == 0) |
1308 | 0 | salt_integer64_2 += 1; |
1309 | | |
1310 | | /* XXX: warning: hard coded proper lengths */ |
1311 | 0 | memcpy(iv, &net_boots, 4); |
1312 | 0 | memcpy(iv+4, &net_time, 4); |
1313 | 0 | memcpy(iv+8, &net_salt_int1, 4); |
1314 | 0 | memcpy(iv+12, &net_salt_int2, 4); |
1315 | |
|
1316 | 0 | memcpy(salt, iv+8, 8); /* only copy the needed portion */ |
1317 | 0 | return 0; |
1318 | 0 | } /* end usm_set_aes_iv() */ |
1319 | | #endif /* HAVE_AES */ |
1320 | | |
1321 | | /*******************************************************************-o-****** |
1322 | | * usm_check_secLevel_vs_protocols |
1323 | | * |
1324 | | * Parameters: |
1325 | | * level |
1326 | | * *authProtocol |
1327 | | * authProtocolLen |
1328 | | * *privProtocol |
1329 | | * privProtocolLen |
1330 | | * |
1331 | | * Returns: |
1332 | | * 0 On success, |
1333 | | * 1 Otherwise. |
1334 | | * |
1335 | | * Same as above but with explicitly named transform types instead of taking |
1336 | | * from the usmUser structure. |
1337 | | */ |
1338 | | static int |
1339 | | usm_check_secLevel_vs_protocols(int level, |
1340 | | const oid * authProtocol, |
1341 | | u_int authProtocolLen, |
1342 | | const oid * privProtocol, |
1343 | | u_int privProtocolLen) |
1344 | 0 | { |
1345 | |
|
1346 | 0 | if (level == SNMP_SEC_LEVEL_AUTHPRIV |
1347 | 0 | && |
1348 | 0 | (netsnmp_oid_equals |
1349 | 0 | (privProtocol, privProtocolLen, usmNoPrivProtocol, |
1350 | 0 | OID_LENGTH(usmNoPrivProtocol)) == 0)) { |
1351 | 0 | DEBUGMSGTL(("usm", "Level: %d\n", level)); |
1352 | 0 | DEBUGMSGTL(("usm", "Auth Protocol: ")); |
1353 | 0 | DEBUGMSGOID(("usm", authProtocol, authProtocolLen)); |
1354 | 0 | DEBUGMSG(("usm", ", Priv Protocol: ")); |
1355 | 0 | DEBUGMSGOID(("usm", privProtocol, privProtocolLen)); |
1356 | 0 | DEBUGMSG(("usm", "\n")); |
1357 | 0 | return 1; |
1358 | 0 | } |
1359 | 0 | if ((level == SNMP_SEC_LEVEL_AUTHPRIV |
1360 | 0 | || level == SNMP_SEC_LEVEL_AUTHNOPRIV) |
1361 | 0 | && |
1362 | 0 | (netsnmp_oid_equals |
1363 | 0 | (authProtocol, authProtocolLen, usmNoAuthProtocol, |
1364 | 0 | OID_LENGTH(usmNoAuthProtocol)) == 0)) { |
1365 | 0 | DEBUGMSGTL(("usm", "Level: %d\n", level)); |
1366 | 0 | DEBUGMSGTL(("usm", "Auth Protocol: ")); |
1367 | 0 | DEBUGMSGOID(("usm", authProtocol, authProtocolLen)); |
1368 | 0 | DEBUGMSG(("usm", ", Priv Protocol: ")); |
1369 | 0 | DEBUGMSGOID(("usm", privProtocol, privProtocolLen)); |
1370 | 0 | DEBUGMSG(("usm", "\n")); |
1371 | 0 | return 1; |
1372 | 0 | } |
1373 | | |
1374 | 0 | return 0; |
1375 | |
|
1376 | 0 | } /* end usm_check_secLevel_vs_protocols() */ |
1377 | | |
1378 | | /*******************************************************************-o-****** |
1379 | | * usm_generate_out_msg |
1380 | | * |
1381 | | * Parameters: |
1382 | | * (See list below...) |
1383 | | * |
1384 | | * Returns: |
1385 | | * SNMPERR_SUCCESS On success. |
1386 | | * SNMPERR_USM_AUTHENTICATIONFAILURE |
1387 | | * SNMPERR_USM_ENCRYPTIONERROR |
1388 | | * SNMPERR_USM_GENERICERROR |
1389 | | * SNMPERR_USM_UNKNOWNSECURITYNAME |
1390 | | * SNMPERR_USM_GENERICERROR |
1391 | | * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL |
1392 | | * |
1393 | | * |
1394 | | * Generates an outgoing message. |
1395 | | * |
1396 | | * XXX Beware of misnomers! |
1397 | | */ |
1398 | | static int |
1399 | | usm_generate_out_msg(int msgProcModel, /* (UNUSED) */ |
1400 | | u_char * globalData, /* IN */ |
1401 | | /* |
1402 | | * Pointer to msg header data will point to the beginning |
1403 | | * * of the entire packet buffer to be transmitted on wire, |
1404 | | * * memory will be contiguous with secParams, typically |
1405 | | * * this pointer will be passed back as beginning of |
1406 | | * * wholeMsg below. asn seq. length is updated w/ new length. |
1407 | | * * |
1408 | | * * While this points to a buffer that should be big enough |
1409 | | * * for the whole message, only the first two parts |
1410 | | * * of the message are completed, namely SNMPv3Message and |
1411 | | * * HeaderData. globalDataLen (next parameter) represents |
1412 | | * * the length of these two completed parts. |
1413 | | */ |
1414 | | size_t globalDataLen, /* IN - Length of msg header data. */ |
1415 | | int maxMsgSize, /* (UNUSED) */ |
1416 | | int secModel, /* (UNUSED) */ |
1417 | | const u_char *secEngineID, /* IN - Pointer snmpEngineID. */ |
1418 | | size_t secEngineIDLen, /* IN - SnmpEngineID length. */ |
1419 | | const char *secName, /* IN - Pointer to securityName.*/ |
1420 | | size_t secNameLen, /* IN - SecurityName length. */ |
1421 | | int secLevel, /* IN - AuthNoPriv, authPriv etc. */ |
1422 | | const u_char *scopedPdu, /* IN */ |
1423 | | /* |
1424 | | * Pointer to scopedPdu will be encrypted by USM if needed |
1425 | | * * and written to packet buffer immediately following |
1426 | | * * securityParameters, entire msg will be authenticated by |
1427 | | * * USM if needed. |
1428 | | */ |
1429 | | size_t scopedPduLen, /* IN - scopedPdu length. */ |
1430 | | const void *secStateRef, /* IN */ |
1431 | | /* |
1432 | | * secStateRef, pointer to cached info provided only for |
1433 | | * * Response, otherwise NULL. |
1434 | | */ |
1435 | | u_char * secParams, /* OUT */ |
1436 | | /* |
1437 | | * BER encoded securityParameters pointer to offset within |
1438 | | * * packet buffer where secParams should be written, the |
1439 | | * * entire BER encoded OCTET STRING (including header) is |
1440 | | * * written here by USM secParams = globalData + |
1441 | | * * globalDataLen. |
1442 | | */ |
1443 | | size_t * secParamsLen, /* IN/OUT - Len available, len returned. */ |
1444 | | u_char ** wholeMsg, /* OUT */ |
1445 | | /* |
1446 | | * Complete authenticated/encrypted message - typically |
1447 | | * * the pointer to start of packet buffer provided in |
1448 | | * * globalData is returned here, could also be a separate |
1449 | | * * buffer. |
1450 | | */ |
1451 | | size_t * wholeMsgLen) |
1452 | 0 | { /* IN/OUT - Len available, len returned. */ |
1453 | 0 | size_t otstlen; |
1454 | 0 | size_t seq_len; |
1455 | 0 | size_t msgAuthParmLen; |
1456 | 0 | size_t msgPrivParmLen; |
1457 | 0 | size_t msgSecParmLen; |
1458 | 0 | size_t authParamsOffset; |
1459 | 0 | size_t privParamsOffset; |
1460 | 0 | size_t datalen; |
1461 | 0 | size_t dataOffset; |
1462 | 0 | size_t theTotalLength; |
1463 | |
|
1464 | 0 | u_char *ptr; |
1465 | 0 | size_t ptr_len; |
1466 | 0 | size_t remaining; |
1467 | 0 | size_t offSet; |
1468 | 0 | u_int boots_uint; |
1469 | 0 | u_int time_uint; |
1470 | 0 | long boots_long; |
1471 | 0 | long time_long; |
1472 | | |
1473 | | /* |
1474 | | * Indirection because secStateRef values override parameters. |
1475 | | * |
1476 | | * None of these are to be free'd - they are either pointing to |
1477 | | * what's in the secStateRef or to something either in the |
1478 | | * actual prarmeter list or the user list. |
1479 | | */ |
1480 | |
|
1481 | 0 | const char *theName = NULL; |
1482 | 0 | u_int theNameLength = 0; |
1483 | 0 | const u_char *theEngineID = NULL; |
1484 | 0 | u_int theEngineIDLength = 0; |
1485 | 0 | u_char *theAuthKey = NULL; |
1486 | 0 | u_int theAuthKeyLength = 0; |
1487 | 0 | const oid *theAuthProtocol = NULL; |
1488 | 0 | u_int theAuthProtocolLength = 0; |
1489 | 0 | u_char *thePrivKey = NULL; |
1490 | 0 | u_int thePrivKeyLength = 0; |
1491 | 0 | const oid *thePrivProtocol = NULL; |
1492 | 0 | u_int thePrivProtocolLength = 0; |
1493 | 0 | int theSecLevel = 0; /* No defined const for bad |
1494 | | * value (other then err). |
1495 | | */ |
1496 | |
|
1497 | 0 | DEBUGMSGTL(("usm", "USM processing has begun.\n")); |
1498 | |
|
1499 | 0 | if (secStateRef != NULL) { |
1500 | | /* |
1501 | | * To hush the compiler for now. XXX |
1502 | | */ |
1503 | 0 | const struct usmStateReference *ref = secStateRef; |
1504 | |
|
1505 | 0 | theName = ref->usr_name; |
1506 | 0 | theNameLength = ref->usr_name_length; |
1507 | 0 | theEngineID = ref->usr_engine_id; |
1508 | 0 | theEngineIDLength = ref->usr_engine_id_length; |
1509 | |
|
1510 | 0 | if (!theEngineIDLength) { |
1511 | 0 | theEngineID = secEngineID; |
1512 | 0 | theEngineIDLength = secEngineIDLen; |
1513 | 0 | } |
1514 | |
|
1515 | 0 | theAuthProtocol = ref->usr_auth_protocol; |
1516 | 0 | theAuthProtocolLength = ref->usr_auth_protocol_length; |
1517 | 0 | theAuthKey = ref->usr_auth_key; |
1518 | 0 | theAuthKeyLength = ref->usr_auth_key_length; |
1519 | 0 | thePrivProtocol = ref->usr_priv_protocol; |
1520 | 0 | thePrivProtocolLength = ref->usr_priv_protocol_length; |
1521 | 0 | thePrivKey = ref->usr_priv_key; |
1522 | 0 | thePrivKeyLength = ref->usr_priv_key_length; |
1523 | 0 | theSecLevel = ref->usr_sec_level; |
1524 | 0 | } |
1525 | | |
1526 | | /* |
1527 | | * Identify the user record. |
1528 | | */ |
1529 | 0 | else { |
1530 | 0 | struct usmUser *user; |
1531 | | |
1532 | | /* |
1533 | | * we do allow an unknown user name for |
1534 | | * unauthenticated requests. |
1535 | | */ |
1536 | 0 | user = usm_get_user2(secEngineID, secEngineIDLen, secName, secNameLen); |
1537 | 0 | if (user == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) { |
1538 | 0 | DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName)); |
1539 | 0 | return SNMPERR_USM_UNKNOWNSECURITYNAME; |
1540 | 0 | } |
1541 | | |
1542 | 0 | theName = secName; |
1543 | 0 | theNameLength = secNameLen; |
1544 | 0 | theEngineID = secEngineID; |
1545 | 0 | theSecLevel = secLevel; |
1546 | 0 | theEngineIDLength = secEngineIDLen; |
1547 | 0 | if (user) { |
1548 | 0 | theAuthProtocol = user->authProtocol; |
1549 | 0 | theAuthProtocolLength = user->authProtocolLen; |
1550 | 0 | theAuthKey = user->authKey; |
1551 | 0 | theAuthKeyLength = user->authKeyLen; |
1552 | 0 | thePrivProtocol = user->privProtocol; |
1553 | 0 | thePrivProtocolLength = user->privProtocolLen; |
1554 | 0 | thePrivKey = user->privKey; |
1555 | 0 | thePrivKeyLength = user->privKeyLen; |
1556 | 0 | } else { |
1557 | | /* |
1558 | | * unknown users can not do authentication (obviously) |
1559 | | */ |
1560 | 0 | theAuthProtocol = usmNoAuthProtocol; |
1561 | 0 | theAuthProtocolLength = |
1562 | 0 | OID_LENGTH(usmNoAuthProtocol); |
1563 | 0 | theAuthKey = NULL; |
1564 | 0 | theAuthKeyLength = 0; |
1565 | 0 | thePrivProtocol = usmNoPrivProtocol; |
1566 | 0 | thePrivProtocolLength = |
1567 | 0 | OID_LENGTH(usmNoPrivProtocol); |
1568 | 0 | thePrivKey = NULL; |
1569 | 0 | thePrivKeyLength = 0; |
1570 | 0 | } |
1571 | 0 | } /* endif -- secStateRef==NULL */ |
1572 | | |
1573 | | |
1574 | | /* |
1575 | | * From here to the end of the function, avoid reference to |
1576 | | * secName, secEngineID, secLevel, and associated lengths. |
1577 | | */ |
1578 | | |
1579 | | |
1580 | | /* |
1581 | | * Check to see if the user can use the requested sec services. |
1582 | | */ |
1583 | 0 | if (usm_check_secLevel_vs_protocols(theSecLevel, |
1584 | 0 | theAuthProtocol, |
1585 | 0 | theAuthProtocolLength, |
1586 | 0 | thePrivProtocol, |
1587 | 0 | thePrivProtocolLength) == 1) { |
1588 | 0 | DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n", |
1589 | 0 | theSecLevel)); |
1590 | 0 | return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL; |
1591 | 0 | } |
1592 | | |
1593 | | |
1594 | | /* |
1595 | | * Retrieve the engine information. |
1596 | | * |
1597 | | * XXX No error is declared in the EoP when sending messages to |
1598 | | * unknown engines, processing continues w/ boots/time == (0,0). |
1599 | | */ |
1600 | 0 | if (get_enginetime(theEngineID, theEngineIDLength, |
1601 | 0 | &boots_uint, &time_uint, FALSE) == -1) { |
1602 | 0 | DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data.")); |
1603 | 0 | } |
1604 | |
|
1605 | 0 | boots_long = boots_uint; |
1606 | 0 | time_long = time_uint; |
1607 | | |
1608 | | |
1609 | | /* |
1610 | | * Set up the Offsets. |
1611 | | */ |
1612 | 0 | if (usm_calc_offsets(globalDataLen, theSecLevel, theEngineIDLength, |
1613 | 0 | theNameLength, scopedPduLen, boots_long, |
1614 | 0 | time_long, &theTotalLength, &authParamsOffset, |
1615 | 0 | &privParamsOffset, &dataOffset, &datalen, |
1616 | 0 | &msgAuthParmLen, &msgPrivParmLen, &otstlen, |
1617 | 0 | &seq_len, &msgSecParmLen) == -1) { |
1618 | 0 | DEBUGMSGTL(("usm", "Failed calculating offsets.\n")); |
1619 | 0 | return SNMPERR_USM_GENERICERROR; |
1620 | 0 | } |
1621 | | |
1622 | | /* |
1623 | | * So, we have the offsets for the three parts that need to be |
1624 | | * determined, and an overall length. Now we need to make |
1625 | | * sure all of this would fit in the outgoing buffer, and |
1626 | | * whether or not we need to make a new buffer, etc. |
1627 | | */ |
1628 | | |
1629 | | |
1630 | | /* |
1631 | | * Set wholeMsg as a pointer to globalData. Sanity check for |
1632 | | * the proper size. |
1633 | | * |
1634 | | * Mark workspace in the message with bytes of all 1's to make it |
1635 | | * easier to find mistakes in raw message dumps. |
1636 | | */ |
1637 | 0 | ptr = *wholeMsg = globalData; |
1638 | 0 | if (theTotalLength > *wholeMsgLen) { |
1639 | 0 | DEBUGMSGTL(("usm", "Message won't fit in buffer.\n")); |
1640 | 0 | return SNMPERR_USM_GENERICERROR; |
1641 | 0 | } |
1642 | | |
1643 | 0 | ptr_len = *wholeMsgLen = theTotalLength; |
1644 | |
|
1645 | | #ifdef NETSNMP_ENABLE_TESTING_CODE |
1646 | | memset(&ptr[globalDataLen], 0xFF, theTotalLength - globalDataLen); |
1647 | | #endif /* NETSNMP_ENABLE_TESTING_CODE */ |
1648 | | |
1649 | | /* |
1650 | | * Do the encryption. |
1651 | | */ |
1652 | 0 | if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
1653 | 0 | size_t encrypted_length = theTotalLength - dataOffset; |
1654 | 0 | size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH); |
1655 | 0 | u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)]; |
1656 | 0 | int priv_type = sc_get_privtype(thePrivProtocol, |
1657 | 0 | thePrivProtocolLength); |
1658 | 0 | #ifdef HAVE_AES |
1659 | 0 | if (USM_CREATE_USER_PRIV_AES == (priv_type & USM_PRIV_MASK_ALG)) { |
1660 | 0 | if (!thePrivKey || |
1661 | 0 | usm_set_aes_iv(salt, &salt_length, |
1662 | 0 | htonl(boots_uint), htonl(time_uint), |
1663 | 0 | &ptr[privParamsOffset]) == -1) { |
1664 | 0 | DEBUGMSGTL(("usm", "Can't set AES iv.\n")); |
1665 | 0 | return SNMPERR_USM_GENERICERROR; |
1666 | 0 | } |
1667 | 0 | } |
1668 | 0 | #endif |
1669 | 0 | #ifndef NETSNMP_DISABLE_DES |
1670 | | /* |
1671 | | * XXX Hardwired to seek into a 1DES private key! |
1672 | | */ |
1673 | 0 | if (USM_CREATE_USER_PRIV_DES == (priv_type & USM_PRIV_MASK_ALG)) { |
1674 | 0 | if (!thePrivKey || |
1675 | 0 | (usm_set_salt(salt, &salt_length, |
1676 | 0 | thePrivKey + 8, thePrivKeyLength - 8, |
1677 | 0 | &ptr[privParamsOffset]) |
1678 | 0 | == -1)) { |
1679 | 0 | DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n")); |
1680 | 0 | return SNMPERR_USM_GENERICERROR; |
1681 | 0 | } |
1682 | 0 | } |
1683 | 0 | #endif |
1684 | | |
1685 | 0 | if (sc_encrypt(thePrivProtocol, thePrivProtocolLength, |
1686 | 0 | thePrivKey, thePrivKeyLength, |
1687 | 0 | salt, salt_length, |
1688 | 0 | scopedPdu, scopedPduLen, |
1689 | 0 | &ptr[dataOffset], &encrypted_length) |
1690 | 0 | != SNMP_ERR_NOERROR) { |
1691 | 0 | DEBUGMSGTL(("usm", "encryption error.\n")); |
1692 | 0 | return SNMPERR_USM_ENCRYPTIONERROR; |
1693 | 0 | } |
1694 | | #ifdef NETSNMP_ENABLE_TESTING_CODE |
1695 | | if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { |
1696 | | dump_chunk("usm/dump", "This data was encrypted:", |
1697 | | scopedPdu, scopedPduLen); |
1698 | | dump_chunk("usm/dump", "salt + Encrypted form:", |
1699 | | salt, salt_length); |
1700 | | dump_chunk("usm/dump", NULL, |
1701 | | &ptr[dataOffset], encrypted_length); |
1702 | | dump_chunk("usm/dump", "*wholeMsg:", |
1703 | | *wholeMsg, theTotalLength); |
1704 | | } |
1705 | | #endif |
1706 | | |
1707 | | |
1708 | 0 | ptr = *wholeMsg; |
1709 | 0 | ptr_len = *wholeMsgLen = theTotalLength; |
1710 | | |
1711 | | |
1712 | | /* |
1713 | | * XXX Sanity check for salt length should be moved up |
1714 | | * under usm_calc_offsets() or tossed. |
1715 | | */ |
1716 | 0 | if ((encrypted_length != (theTotalLength - dataOffset)) |
1717 | 0 | || (salt_length != msgPrivParmLen)) { |
1718 | 0 | DEBUGMSGTL(("usm", "encryption length error.\n")); |
1719 | 0 | return SNMPERR_USM_ENCRYPTIONERROR; |
1720 | 0 | } |
1721 | | |
1722 | 0 | DEBUGMSGTL(("usm", "Encryption successful.\n")); |
1723 | 0 | } |
1724 | | |
1725 | | /* |
1726 | | * No encryption for you! |
1727 | | */ |
1728 | 0 | else { |
1729 | 0 | memcpy(&ptr[dataOffset], scopedPdu, scopedPduLen); |
1730 | 0 | } |
1731 | | |
1732 | | |
1733 | | |
1734 | | /* |
1735 | | * Start filling in the other fields (in prep for authentication). |
1736 | | * |
1737 | | * offSet is an octet string header, which is different from all |
1738 | | * the other headers. |
1739 | | */ |
1740 | 0 | remaining = ptr_len - globalDataLen; |
1741 | |
|
1742 | 0 | offSet = ptr_len - remaining; |
1743 | 0 | asn_build_header(&ptr[offSet], &remaining, |
1744 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1745 | 0 | ASN_OCTET_STR), otstlen); |
1746 | |
|
1747 | 0 | offSet = ptr_len - remaining; |
1748 | 0 | asn_build_sequence(&ptr[offSet], &remaining, |
1749 | 0 | (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len); |
1750 | |
|
1751 | 0 | offSet = ptr_len - remaining; |
1752 | 0 | DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID"); |
1753 | 0 | asn_build_string(&ptr[offSet], &remaining, |
1754 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1755 | 0 | ASN_OCTET_STR), theEngineID, |
1756 | 0 | theEngineIDLength); |
1757 | 0 | DEBUGINDENTLESS(); |
1758 | |
|
1759 | 0 | offSet = ptr_len - remaining; |
1760 | 0 | DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots"); |
1761 | 0 | asn_build_int(&ptr[offSet], &remaining, |
1762 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), |
1763 | 0 | &boots_long, sizeof(long)); |
1764 | 0 | DEBUGINDENTLESS(); |
1765 | |
|
1766 | 0 | offSet = ptr_len - remaining; |
1767 | 0 | DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime"); |
1768 | 0 | asn_build_int(&ptr[offSet], &remaining, |
1769 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), |
1770 | 0 | &time_long, sizeof(long)); |
1771 | 0 | DEBUGINDENTLESS(); |
1772 | |
|
1773 | 0 | offSet = ptr_len - remaining; |
1774 | 0 | DEBUGDUMPHEADER("send", "msgUserName"); |
1775 | 0 | asn_build_string(&ptr[offSet], &remaining, |
1776 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1777 | 0 | ASN_OCTET_STR), (const u_char *) theName, |
1778 | 0 | theNameLength); |
1779 | 0 | DEBUGINDENTLESS(); |
1780 | | |
1781 | | |
1782 | | /* |
1783 | | * Note: if there is no authentication being done, |
1784 | | * msgAuthParmLen is 0, and there is no effect (other than |
1785 | | * inserting a zero-length header) of the following |
1786 | | * statements. |
1787 | | */ |
1788 | |
|
1789 | 0 | offSet = ptr_len - remaining; |
1790 | 0 | asn_build_header(&ptr[offSet], |
1791 | 0 | &remaining, |
1792 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1793 | 0 | ASN_OCTET_STR), msgAuthParmLen); |
1794 | |
|
1795 | 0 | if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV |
1796 | 0 | || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
1797 | 0 | offSet = ptr_len - remaining; |
1798 | 0 | memset(&ptr[offSet], 0, msgAuthParmLen); |
1799 | 0 | } |
1800 | |
|
1801 | 0 | remaining -= msgAuthParmLen; |
1802 | | |
1803 | | |
1804 | | /* |
1805 | | * Note: if there is no encryption being done, msgPrivParmLen |
1806 | | * is 0, and there is no effect (other than inserting a |
1807 | | * zero-length header) of the following statements. |
1808 | | */ |
1809 | |
|
1810 | 0 | offSet = ptr_len - remaining; |
1811 | 0 | asn_build_header(&ptr[offSet], |
1812 | 0 | &remaining, |
1813 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1814 | 0 | ASN_OCTET_STR), msgPrivParmLen); |
1815 | |
|
1816 | 0 | remaining -= msgPrivParmLen; /* Skipping the IV already there. */ |
1817 | | |
1818 | | |
1819 | | /* |
1820 | | * For privacy, need to add the octet string header for it. |
1821 | | */ |
1822 | 0 | if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
1823 | 0 | offSet = ptr_len - remaining; |
1824 | 0 | asn_build_header(&ptr[offSet], |
1825 | 0 | &remaining, |
1826 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1827 | 0 | ASN_OCTET_STR), |
1828 | 0 | theTotalLength - dataOffset); |
1829 | 0 | } |
1830 | | |
1831 | | |
1832 | | /* |
1833 | | * Adjust overall length and store it as the first SEQ length |
1834 | | * of the SNMPv3Message. |
1835 | | * |
1836 | | * FIX 4 is a magic number! |
1837 | | */ |
1838 | 0 | remaining = theTotalLength; |
1839 | 0 | asn_build_sequence(ptr, &remaining, |
1840 | 0 | (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), |
1841 | 0 | theTotalLength - 4); |
1842 | | |
1843 | | |
1844 | | /* |
1845 | | * Now, time to consider / do authentication. |
1846 | | */ |
1847 | 0 | if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV |
1848 | 0 | || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
1849 | 0 | size_t temp_sig_len = msgAuthParmLen; |
1850 | 0 | u_char *temp_sig = (u_char *) malloc(temp_sig_len); |
1851 | |
|
1852 | 0 | if (temp_sig == NULL) { |
1853 | 0 | DEBUGMSGTL(("usm", "Out of memory.\n")); |
1854 | 0 | return SNMPERR_USM_GENERICERROR; |
1855 | 0 | } |
1856 | | |
1857 | 0 | if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength, |
1858 | 0 | theAuthKey, theAuthKeyLength, |
1859 | 0 | ptr, ptr_len, temp_sig, &temp_sig_len) |
1860 | 0 | != SNMP_ERR_NOERROR) { |
1861 | | /* |
1862 | | * FIX temp_sig_len defined?! |
1863 | | */ |
1864 | 0 | SNMP_ZERO(temp_sig, temp_sig_len); |
1865 | 0 | SNMP_FREE(temp_sig); |
1866 | 0 | DEBUGMSGTL(("usm", "Signing failed.\n")); |
1867 | 0 | return SNMPERR_USM_AUTHENTICATIONFAILURE; |
1868 | 0 | } |
1869 | | |
1870 | 0 | if (temp_sig_len != msgAuthParmLen) { |
1871 | 0 | SNMP_ZERO(temp_sig, temp_sig_len); |
1872 | 0 | SNMP_FREE(temp_sig); |
1873 | 0 | DEBUGMSGTL(("usm", "Signing lengths failed.\n")); |
1874 | 0 | return SNMPERR_USM_AUTHENTICATIONFAILURE; |
1875 | 0 | } |
1876 | | |
1877 | 0 | memcpy(&ptr[authParamsOffset], temp_sig, msgAuthParmLen); |
1878 | |
|
1879 | 0 | SNMP_ZERO(temp_sig, temp_sig_len); |
1880 | 0 | SNMP_FREE(temp_sig); |
1881 | |
|
1882 | 0 | } |
1883 | | |
1884 | | /* |
1885 | | * endif -- create keyed hash |
1886 | | */ |
1887 | | |
1888 | 0 | DEBUGMSGTL(("usm", "USM processing completed.\n")); |
1889 | |
|
1890 | 0 | return SNMPERR_SUCCESS; |
1891 | |
|
1892 | 0 | } /* end usm_generate_out_msg() */ |
1893 | | |
1894 | | static int |
1895 | | usm_secmod_generate_out_msg(struct snmp_secmod_outgoing_params *parms) |
1896 | 0 | { |
1897 | 0 | if (!parms) |
1898 | 0 | return SNMPERR_GENERR; |
1899 | | |
1900 | 0 | return usm_generate_out_msg(parms->msgProcModel, |
1901 | 0 | parms->globalData, parms->globalDataLen, |
1902 | 0 | parms->maxMsgSize, parms->secModel, |
1903 | 0 | parms->secEngineID, parms->secEngineIDLen, |
1904 | 0 | parms->secName, parms->secNameLen, |
1905 | 0 | parms->secLevel, |
1906 | 0 | parms->scopedPdu, parms->scopedPduLen, |
1907 | 0 | parms->secStateRef, |
1908 | 0 | parms->secParams, parms->secParamsLen, |
1909 | 0 | parms->wholeMsg, parms->wholeMsgLen); |
1910 | 0 | } |
1911 | | |
1912 | | #ifdef NETSNMP_USE_REVERSE_ASNENCODING |
1913 | | static int |
1914 | | usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */ |
1915 | | u_char * globalData, /* IN */ |
1916 | | /* |
1917 | | * points at the msgGlobalData, which is of length given by next |
1918 | | * parameter. |
1919 | | */ |
1920 | | size_t globalDataLen, /* IN - Length of msg header data. */ |
1921 | | int maxMsgSize, /* (UNUSED) */ |
1922 | | int secModel, /* (UNUSED) */ |
1923 | | const u_char *secEngineID, /* IN - Pointer snmpEngineID.*/ |
1924 | | size_t secEngineIDLen, /* IN - SnmpEngineID length. */ |
1925 | | const char *secName, /* IN - Pointer to securityName.*/ |
1926 | | size_t secNameLen, /* IN - SecurityName length. */ |
1927 | | int secLevel, /* IN - AuthNoPriv, authPriv etc. */ |
1928 | | const u_char *scopedPdu, /* IN */ |
1929 | | /* |
1930 | | * Pointer to scopedPdu will be encrypted by USM if needed |
1931 | | * * and written to packet buffer immediately following |
1932 | | * * securityParameters, entire msg will be authenticated by |
1933 | | * * USM if needed. |
1934 | | */ |
1935 | | size_t scopedPduLen, /* IN - scopedPdu length. */ |
1936 | | const void *secStateRef, /* IN */ |
1937 | | /* |
1938 | | * secStateRef, pointer to cached info provided only for |
1939 | | * * Response, otherwise NULL. |
1940 | | */ |
1941 | | u_char ** wholeMsg, /* IN/OUT */ |
1942 | | /* |
1943 | | * Points at the pointer to the packet buffer, which might get extended |
1944 | | * if necessary via realloc(). |
1945 | | */ |
1946 | | size_t * wholeMsgLen, /* IN/OUT */ |
1947 | | /* |
1948 | | * Length of the entire packet buffer, **not** the length of the |
1949 | | * packet. |
1950 | | */ |
1951 | | size_t * offset /* IN/OUT */ |
1952 | | /* |
1953 | | * Offset from the end of the packet buffer to the start of the packet, |
1954 | | * also known as the packet length. |
1955 | | */ |
1956 | | ) |
1957 | 0 | { |
1958 | 0 | size_t msgAuthParmLen = 0; |
1959 | 0 | u_int boots_uint; |
1960 | 0 | u_int time_uint; |
1961 | 0 | long boots_long; |
1962 | 0 | long time_long; |
1963 | | |
1964 | | /* |
1965 | | * Indirection because secStateRef values override parameters. |
1966 | | * |
1967 | | * None of these are to be free'd - they are either pointing to |
1968 | | * what's in the secStateRef or to something either in the |
1969 | | * actual parameter list or the user list. |
1970 | | */ |
1971 | |
|
1972 | 0 | const char *theName = NULL; |
1973 | 0 | u_int theNameLength = 0; |
1974 | 0 | const u_char *theEngineID = NULL; |
1975 | 0 | u_int theEngineIDLength = 0; |
1976 | 0 | u_char *theAuthKey = NULL; |
1977 | 0 | u_int theAuthKeyLength = 0; |
1978 | 0 | const oid *theAuthProtocol = NULL; |
1979 | 0 | u_int theAuthProtocolLength = 0; |
1980 | 0 | u_char *thePrivKey = NULL; |
1981 | 0 | u_int thePrivKeyLength = 0; |
1982 | 0 | const oid *thePrivProtocol = NULL; |
1983 | 0 | u_int thePrivProtocolLength = 0; |
1984 | 0 | int theSecLevel = 0; /* No defined const for bad |
1985 | | * value (other then err). */ |
1986 | 0 | size_t salt_length = 0, save_salt_length = 0; |
1987 | 0 | u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)]; |
1988 | 0 | u_char authParams[USM_MAX_AUTHSIZE]; |
1989 | 0 | u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)]; |
1990 | 0 | size_t sp_offset = 0, mac_offset = 0; |
1991 | 0 | int rc = 0; |
1992 | |
|
1993 | 0 | DEBUGMSGTL(("usm", "USM processing has begun (offset %d)\n", (int)*offset)); |
1994 | |
|
1995 | 0 | if (secStateRef != NULL) { |
1996 | | /* |
1997 | | * To hush the compiler for now. XXX |
1998 | | */ |
1999 | 0 | const struct usmStateReference *ref = secStateRef; |
2000 | |
|
2001 | 0 | theName = ref->usr_name; |
2002 | 0 | theNameLength = ref->usr_name_length; |
2003 | 0 | theEngineID = ref->usr_engine_id; |
2004 | 0 | theEngineIDLength = ref->usr_engine_id_length; |
2005 | |
|
2006 | 0 | if (!theEngineIDLength) { |
2007 | 0 | theEngineID = secEngineID; |
2008 | 0 | theEngineIDLength = secEngineIDLen; |
2009 | 0 | } |
2010 | |
|
2011 | 0 | theAuthProtocol = ref->usr_auth_protocol; |
2012 | 0 | theAuthProtocolLength = ref->usr_auth_protocol_length; |
2013 | 0 | theAuthKey = ref->usr_auth_key; |
2014 | 0 | theAuthKeyLength = ref->usr_auth_key_length; |
2015 | 0 | thePrivProtocol = ref->usr_priv_protocol; |
2016 | 0 | thePrivProtocolLength = ref->usr_priv_protocol_length; |
2017 | 0 | thePrivKey = ref->usr_priv_key; |
2018 | 0 | thePrivKeyLength = ref->usr_priv_key_length; |
2019 | 0 | theSecLevel = ref->usr_sec_level; |
2020 | 0 | } |
2021 | | |
2022 | | /* |
2023 | | * * Identify the user record. |
2024 | | */ |
2025 | 0 | else { |
2026 | 0 | struct usmUser *user; |
2027 | | |
2028 | | /* |
2029 | | * we do allow an unknown user name for |
2030 | | * unauthenticated requests. |
2031 | | */ |
2032 | 0 | user = usm_get_user2(secEngineID, secEngineIDLen, secName, secNameLen); |
2033 | 0 | if (user == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) { |
2034 | 0 | DEBUGMSGTL(("usm", "Unknown User\n")); |
2035 | 0 | return SNMPERR_USM_UNKNOWNSECURITYNAME; |
2036 | 0 | } |
2037 | | |
2038 | 0 | theName = secName; |
2039 | 0 | theNameLength = secNameLen; |
2040 | 0 | theEngineID = secEngineID; |
2041 | 0 | theSecLevel = secLevel; |
2042 | 0 | theEngineIDLength = secEngineIDLen; |
2043 | 0 | if (user) { |
2044 | 0 | theAuthProtocol = user->authProtocol; |
2045 | 0 | theAuthProtocolLength = user->authProtocolLen; |
2046 | 0 | theAuthKey = user->authKey; |
2047 | 0 | theAuthKeyLength = user->authKeyLen; |
2048 | 0 | thePrivProtocol = user->privProtocol; |
2049 | 0 | thePrivProtocolLength = user->privProtocolLen; |
2050 | 0 | thePrivKey = user->privKey; |
2051 | 0 | thePrivKeyLength = user->privKeyLen; |
2052 | 0 | } else { |
2053 | | /* |
2054 | | * unknown users can not do authentication (obviously) |
2055 | | */ |
2056 | 0 | theAuthProtocol = usmNoAuthProtocol; |
2057 | 0 | theAuthProtocolLength = |
2058 | 0 | OID_LENGTH(usmNoAuthProtocol); |
2059 | 0 | theAuthKey = NULL; |
2060 | 0 | theAuthKeyLength = 0; |
2061 | 0 | thePrivProtocol = usmNoPrivProtocol; |
2062 | 0 | thePrivProtocolLength = |
2063 | 0 | OID_LENGTH(usmNoPrivProtocol); |
2064 | 0 | thePrivKey = NULL; |
2065 | 0 | thePrivKeyLength = 0; |
2066 | 0 | } |
2067 | 0 | } /* endif -- secStateRef==NULL */ |
2068 | | |
2069 | | |
2070 | | /* |
2071 | | * From here to the end of the function, avoid reference to |
2072 | | * secName, secEngineID, secLevel, and associated lengths. |
2073 | | */ |
2074 | | |
2075 | | |
2076 | | /* |
2077 | | * Check to see if the user can use the requested sec services. |
2078 | | */ |
2079 | 0 | if (usm_check_secLevel_vs_protocols(theSecLevel, |
2080 | 0 | theAuthProtocol, |
2081 | 0 | theAuthProtocolLength, |
2082 | 0 | thePrivProtocol, |
2083 | 0 | thePrivProtocolLength) == 1) { |
2084 | 0 | DEBUGMSGTL(("usm", "Unsupported Security Level or type (%d)\n", |
2085 | 0 | theSecLevel)); |
2086 | |
|
2087 | 0 | return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL; |
2088 | 0 | } |
2089 | | |
2090 | | |
2091 | | /* |
2092 | | * * Retrieve the engine information. |
2093 | | * * |
2094 | | * * XXX No error is declared in the EoP when sending messages to |
2095 | | * * unknown engines, processing continues w/ boots/time == (0,0). |
2096 | | */ |
2097 | 0 | if (get_enginetime(theEngineID, theEngineIDLength, |
2098 | 0 | &boots_uint, &time_uint, FALSE) == -1) { |
2099 | 0 | DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data.")); |
2100 | 0 | } |
2101 | |
|
2102 | 0 | boots_long = boots_uint; |
2103 | 0 | time_long = time_uint; |
2104 | |
|
2105 | 0 | if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
2106 | | /* |
2107 | | * Initially assume that the ciphertext will end up the same size as |
2108 | | * the plaintext plus some padding. Really sc_encrypt ought to be able |
2109 | | * to grow this for us, a la asn_realloc_rbuild_<type> functions, but |
2110 | | * this will do for now. |
2111 | | */ |
2112 | 0 | u_char *ciphertext = NULL; |
2113 | 0 | size_t ciphertextlen = scopedPduLen + 64; |
2114 | 0 | int priv_type = sc_get_privtype(thePrivProtocol, |
2115 | 0 | thePrivProtocolLength); |
2116 | |
|
2117 | 0 | if ((ciphertext = (u_char *) malloc(ciphertextlen)) == NULL) { |
2118 | 0 | DEBUGMSGTL(("usm", |
2119 | 0 | "couldn't malloc %d bytes for encrypted PDU\n", |
2120 | 0 | (int)ciphertextlen)); |
2121 | 0 | return SNMPERR_MALLOC; |
2122 | 0 | } |
2123 | | |
2124 | | /* |
2125 | | * XXX Hardwired to seek into a 1DES private key! |
2126 | | */ |
2127 | 0 | #ifdef HAVE_AES |
2128 | 0 | if (USM_CREATE_USER_PRIV_AES == (priv_type & USM_PRIV_MASK_ALG)) { |
2129 | 0 | salt_length = BYTESIZE(USM_AES_SALT_LENGTH); |
2130 | 0 | save_salt_length = BYTESIZE(USM_AES_SALT_LENGTH)/2; |
2131 | 0 | if (!thePrivKey || |
2132 | 0 | usm_set_aes_iv(salt, &salt_length, |
2133 | 0 | htonl(boots_uint), htonl(time_uint), |
2134 | 0 | iv) == -1) { |
2135 | 0 | DEBUGMSGTL(("usm", "Can't set AES iv.\n")); |
2136 | 0 | SNMP_FREE(ciphertext); |
2137 | 0 | return SNMPERR_USM_GENERICERROR; |
2138 | 0 | } |
2139 | 0 | } |
2140 | 0 | #endif |
2141 | 0 | #ifndef NETSNMP_DISABLE_DES |
2142 | 0 | if (USM_CREATE_USER_PRIV_DES == (priv_type & USM_PRIV_MASK_ALG)) { |
2143 | 0 | salt_length = BYTESIZE(USM_DES_SALT_LENGTH); |
2144 | 0 | save_salt_length = BYTESIZE(USM_DES_SALT_LENGTH); |
2145 | 0 | if (!thePrivKey || (usm_set_salt(salt, &salt_length, |
2146 | 0 | thePrivKey + 8, |
2147 | 0 | thePrivKeyLength - 8, |
2148 | 0 | iv) == -1)) { |
2149 | 0 | DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n")); |
2150 | 0 | SNMP_FREE(ciphertext); |
2151 | 0 | return SNMPERR_USM_GENERICERROR; |
2152 | 0 | } |
2153 | 0 | } |
2154 | 0 | #endif |
2155 | | #ifdef NETSNMP_ENABLE_TESTING_CODE |
2156 | | if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { |
2157 | | dump_chunk("usm/dump", "This data was encrypted:", |
2158 | | scopedPdu, scopedPduLen); |
2159 | | } |
2160 | | #endif |
2161 | | |
2162 | 0 | if (sc_encrypt(thePrivProtocol, thePrivProtocolLength, |
2163 | 0 | thePrivKey, thePrivKeyLength, |
2164 | 0 | salt, salt_length, |
2165 | 0 | scopedPdu, scopedPduLen, |
2166 | 0 | ciphertext, &ciphertextlen) != SNMP_ERR_NOERROR) { |
2167 | 0 | DEBUGMSGTL(("usm", "encryption error.\n")); |
2168 | 0 | SNMP_FREE(ciphertext); |
2169 | 0 | return SNMPERR_USM_ENCRYPTIONERROR; |
2170 | 0 | } |
2171 | | |
2172 | | /* |
2173 | | * Write the encrypted scopedPdu back into the packet buffer. |
2174 | | */ |
2175 | | |
2176 | 0 | *offset = 0; |
2177 | 0 | rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, |
2178 | 0 | (u_char) (ASN_UNIVERSAL | |
2179 | 0 | ASN_PRIMITIVE | |
2180 | 0 | ASN_OCTET_STR), |
2181 | 0 | ciphertext, ciphertextlen); |
2182 | 0 | if (rc == 0) { |
2183 | 0 | DEBUGMSGTL(("usm", "Encryption failed.\n")); |
2184 | 0 | SNMP_FREE(ciphertext); |
2185 | 0 | return SNMPERR_USM_ENCRYPTIONERROR; |
2186 | 0 | } |
2187 | | |
2188 | | #ifdef NETSNMP_ENABLE_TESTING_CODE |
2189 | | if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { |
2190 | | dump_chunk("usm/dump", "salt + Encrypted form: ", salt, |
2191 | | salt_length); |
2192 | | dump_chunk("usm/dump", "wholeMsg:", |
2193 | | (*wholeMsg + *wholeMsgLen - *offset), *offset); |
2194 | | } |
2195 | | #endif |
2196 | | |
2197 | 0 | DEBUGMSGTL(("usm", "Encryption successful.\n")); |
2198 | 0 | SNMP_FREE(ciphertext); |
2199 | 0 | } else { |
2200 | | /* |
2201 | | * theSecLevel != SNMP_SEC_LEVEL_AUTHPRIV |
2202 | | */ |
2203 | 0 | } |
2204 | | |
2205 | | /* |
2206 | | * Start encoding the msgSecurityParameters. |
2207 | | */ |
2208 | | |
2209 | 0 | sp_offset = *offset; |
2210 | |
|
2211 | 0 | DEBUGDUMPHEADER("send", "msgPrivacyParameters"); |
2212 | | /* |
2213 | | * msgPrivacyParameters (warning: assumes DES salt). |
2214 | | */ |
2215 | 0 | rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, |
2216 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2217 | 0 | | ASN_OCTET_STR), |
2218 | 0 | iv, |
2219 | 0 | save_salt_length); |
2220 | 0 | DEBUGINDENTLESS(); |
2221 | 0 | if (rc == 0) { |
2222 | 0 | DEBUGMSGTL(("usm", "building privParams failed.\n")); |
2223 | 0 | return SNMPERR_TOO_LONG; |
2224 | 0 | } |
2225 | | |
2226 | 0 | DEBUGDUMPHEADER("send", "msgAuthenticationParameters"); |
2227 | | /* |
2228 | | * msgAuthenticationParameters. |
2229 | | */ |
2230 | 0 | if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV |
2231 | 0 | || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
2232 | 0 | memset(authParams, 0, sizeof(authParams)); |
2233 | 0 | msgAuthParmLen = |
2234 | 0 | sc_get_auth_maclen(sc_get_authtype(theAuthProtocol, |
2235 | 0 | theAuthProtocolLength)); |
2236 | 0 | } |
2237 | |
|
2238 | 0 | rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, |
2239 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2240 | 0 | | ASN_OCTET_STR), authParams, |
2241 | 0 | msgAuthParmLen); |
2242 | 0 | DEBUGINDENTLESS(); |
2243 | 0 | if (rc == 0) { |
2244 | 0 | DEBUGMSGTL(("usm", "building authParams failed.\n")); |
2245 | 0 | return SNMPERR_TOO_LONG; |
2246 | 0 | } |
2247 | | |
2248 | | /* |
2249 | | * Remember where to put the actual HMAC we calculate later on. An |
2250 | | * encoded OCTET STRING of length USM_MD5_AND_SHA_AUTH_LEN has an ASN.1 |
2251 | | * header of length 2, hence the fudge factor. This works as long as |
2252 | | * auth lengths stay < 127. |
2253 | | */ |
2254 | 0 | mac_offset = *offset - 2; |
2255 | | |
2256 | | /* |
2257 | | * msgUserName. |
2258 | | */ |
2259 | 0 | DEBUGDUMPHEADER("send", "msgUserName"); |
2260 | 0 | rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, |
2261 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2262 | 0 | | ASN_OCTET_STR), |
2263 | 0 | (const u_char *) theName, theNameLength); |
2264 | 0 | DEBUGINDENTLESS(); |
2265 | 0 | if (rc == 0) { |
2266 | 0 | DEBUGMSGTL(("usm", "building authParams failed.\n")); |
2267 | 0 | return SNMPERR_TOO_LONG; |
2268 | 0 | } |
2269 | | |
2270 | | /* |
2271 | | * msgAuthoritativeEngineTime. |
2272 | | */ |
2273 | 0 | DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime"); |
2274 | 0 | rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1, |
2275 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
2276 | 0 | ASN_INTEGER), &time_long, |
2277 | 0 | sizeof(long)); |
2278 | 0 | DEBUGINDENTLESS(); |
2279 | 0 | if (rc == 0) { |
2280 | 0 | DEBUGMSGTL(("usm", |
2281 | 0 | "building msgAuthoritativeEngineTime failed.\n")); |
2282 | 0 | return SNMPERR_TOO_LONG; |
2283 | 0 | } |
2284 | | |
2285 | | /* |
2286 | | * msgAuthoritativeEngineBoots. |
2287 | | */ |
2288 | 0 | DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots"); |
2289 | 0 | rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1, |
2290 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
2291 | 0 | ASN_INTEGER), &boots_long, |
2292 | 0 | sizeof(long)); |
2293 | 0 | DEBUGINDENTLESS(); |
2294 | 0 | if (rc == 0) { |
2295 | 0 | DEBUGMSGTL(("usm", |
2296 | 0 | "building msgAuthoritativeEngineBoots failed.\n")); |
2297 | 0 | return SNMPERR_TOO_LONG; |
2298 | 0 | } |
2299 | | |
2300 | 0 | DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID"); |
2301 | 0 | rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, |
2302 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2303 | 0 | | ASN_OCTET_STR), theEngineID, |
2304 | 0 | theEngineIDLength); |
2305 | 0 | DEBUGINDENTLESS(); |
2306 | 0 | if (rc == 0) { |
2307 | 0 | DEBUGMSGTL(("usm", "building msgAuthoritativeEngineID failed.\n")); |
2308 | 0 | return SNMPERR_TOO_LONG; |
2309 | 0 | } |
2310 | | |
2311 | | /* |
2312 | | * USM msgSecurityParameters sequence header |
2313 | | */ |
2314 | 0 | rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1, |
2315 | 0 | (u_char) (ASN_SEQUENCE | |
2316 | 0 | ASN_CONSTRUCTOR), |
2317 | 0 | *offset - sp_offset); |
2318 | 0 | if (rc == 0) { |
2319 | 0 | DEBUGMSGTL(("usm", "building usm security parameters failed.\n")); |
2320 | 0 | return SNMPERR_TOO_LONG; |
2321 | 0 | } |
2322 | | |
2323 | | /* |
2324 | | * msgSecurityParameters OCTET STRING wrapper. |
2325 | | */ |
2326 | 0 | rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1, |
2327 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2328 | 0 | | ASN_OCTET_STR), |
2329 | 0 | *offset - sp_offset); |
2330 | |
|
2331 | 0 | if (rc == 0) { |
2332 | 0 | DEBUGMSGTL(("usm", "building msgSecurityParameters failed.\n")); |
2333 | 0 | return SNMPERR_TOO_LONG; |
2334 | 0 | } |
2335 | | |
2336 | | /* |
2337 | | * Copy in the msgGlobalData and msgVersion. |
2338 | | */ |
2339 | 0 | while ((*wholeMsgLen - *offset) < globalDataLen) { |
2340 | 0 | if (!asn_realloc(wholeMsg, wholeMsgLen)) { |
2341 | 0 | DEBUGMSGTL(("usm", "building global data failed.\n")); |
2342 | 0 | return SNMPERR_TOO_LONG; |
2343 | 0 | } |
2344 | 0 | } |
2345 | | |
2346 | 0 | *offset += globalDataLen; |
2347 | 0 | memcpy(*wholeMsg + *wholeMsgLen - *offset, globalData, globalDataLen); |
2348 | | |
2349 | | /* |
2350 | | * Total packet sequence. |
2351 | | */ |
2352 | 0 | rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1, |
2353 | 0 | (u_char) (ASN_SEQUENCE | |
2354 | 0 | ASN_CONSTRUCTOR), *offset); |
2355 | 0 | if (rc == 0) { |
2356 | 0 | DEBUGMSGTL(("usm", "building master packet sequence failed.\n")); |
2357 | 0 | return SNMPERR_TOO_LONG; |
2358 | 0 | } |
2359 | | |
2360 | | /* |
2361 | | * Now consider / do authentication. |
2362 | | */ |
2363 | | |
2364 | 0 | if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || |
2365 | 0 | theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
2366 | 0 | size_t temp_sig_len = msgAuthParmLen; |
2367 | 0 | u_char *temp_sig = (u_char *) malloc(temp_sig_len); |
2368 | 0 | u_char *proto_msg = *wholeMsg + *wholeMsgLen - *offset; |
2369 | 0 | size_t proto_msg_len = *offset; |
2370 | | |
2371 | |
|
2372 | 0 | if (temp_sig == NULL) { |
2373 | 0 | DEBUGMSGTL(("usm", "Out of memory.\n")); |
2374 | 0 | return SNMPERR_USM_GENERICERROR; |
2375 | 0 | } |
2376 | | |
2377 | 0 | if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength, |
2378 | 0 | theAuthKey, theAuthKeyLength, |
2379 | 0 | proto_msg, proto_msg_len, |
2380 | 0 | temp_sig, &temp_sig_len) |
2381 | 0 | != SNMP_ERR_NOERROR) { |
2382 | 0 | SNMP_FREE(temp_sig); |
2383 | 0 | DEBUGMSGTL(("usm", "Signing failed.\n")); |
2384 | 0 | return SNMPERR_USM_AUTHENTICATIONFAILURE; |
2385 | 0 | } |
2386 | | |
2387 | 0 | if (temp_sig_len != msgAuthParmLen) { |
2388 | 0 | SNMP_FREE(temp_sig); |
2389 | 0 | DEBUGMSGTL(("usm", "Signing lengths failed.\n")); |
2390 | 0 | return SNMPERR_USM_AUTHENTICATIONFAILURE; |
2391 | 0 | } |
2392 | | |
2393 | 0 | memcpy(*wholeMsg + *wholeMsgLen - mac_offset, temp_sig, |
2394 | 0 | msgAuthParmLen); |
2395 | 0 | SNMP_FREE(temp_sig); |
2396 | 0 | } |
2397 | | /* |
2398 | | * endif -- create keyed hash |
2399 | | */ |
2400 | 0 | DEBUGMSGTL(("usm", "USM processing completed.\n")); |
2401 | 0 | return SNMPERR_SUCCESS; |
2402 | 0 | } /* end usm_rgenerate_out_msg() */ |
2403 | | |
2404 | | static int |
2405 | | usm_secmod_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms) |
2406 | 0 | { |
2407 | 0 | if (!parms) |
2408 | 0 | return SNMPERR_GENERR; |
2409 | | |
2410 | 0 | return usm_rgenerate_out_msg(parms->msgProcModel, |
2411 | 0 | parms->globalData, parms->globalDataLen, |
2412 | 0 | parms->maxMsgSize, parms->secModel, |
2413 | 0 | parms->secEngineID, parms->secEngineIDLen, |
2414 | 0 | parms->secName, parms->secNameLen, |
2415 | 0 | parms->secLevel, |
2416 | 0 | parms->scopedPdu, parms->scopedPduLen, |
2417 | 0 | parms->secStateRef, |
2418 | 0 | parms->wholeMsg, parms->wholeMsgLen, |
2419 | 0 | parms->wholeMsgOffset); |
2420 | 0 | } |
2421 | | #endif /* */ |
2422 | | |
2423 | | /*******************************************************************-o-****** |
2424 | | * usm_parse_security_parameters |
2425 | | * |
2426 | | * Parameters: |
2427 | | * (See list below...) |
2428 | | * |
2429 | | * Returns: |
2430 | | * 0 On success, |
2431 | | * -1 Otherwise. |
2432 | | * |
2433 | | * tab stop 4 |
2434 | | * |
2435 | | * Extracts values from the security header and data portions of the |
2436 | | * incoming buffer. |
2437 | | */ |
2438 | | static int |
2439 | | usm_parse_security_parameters(u_char * secParams, |
2440 | | size_t remaining, |
2441 | | u_char * secEngineID, |
2442 | | size_t * secEngineIDLen, |
2443 | | u_int * boots_uint, |
2444 | | u_int * time_uint, |
2445 | | char *secName, |
2446 | | size_t * secNameLen, |
2447 | | u_char * signature, |
2448 | | size_t * signature_length, |
2449 | | u_char * salt, |
2450 | | size_t * salt_length, u_char ** data_ptr) |
2451 | 0 | { |
2452 | 0 | u_char *parse_ptr = secParams; |
2453 | 0 | u_char *value_ptr; |
2454 | 0 | u_char *next_ptr; |
2455 | 0 | u_char type_value; |
2456 | |
|
2457 | 0 | size_t octet_string_length = remaining; |
2458 | 0 | size_t sequence_length; |
2459 | 0 | size_t remaining_bytes; |
2460 | |
|
2461 | 0 | long boots_long; |
2462 | 0 | long time_long; |
2463 | |
|
2464 | 0 | u_int origNameLen; |
2465 | | |
2466 | | |
2467 | | /* |
2468 | | * Eat the first octet header. |
2469 | | */ |
2470 | 0 | if ((value_ptr = asn_parse_sequence(parse_ptr, &octet_string_length, |
2471 | 0 | &type_value, |
2472 | 0 | (ASN_UNIVERSAL | ASN_PRIMITIVE | |
2473 | 0 | ASN_OCTET_STR), |
2474 | 0 | "usm first octet")) == NULL) { |
2475 | | /* |
2476 | | * RETURN parse error |
2477 | 0 | */ return -1; |
2478 | 0 | } |
2479 | | |
2480 | | |
2481 | | /* |
2482 | | * Eat the sequence header. |
2483 | | */ |
2484 | 0 | parse_ptr = value_ptr; |
2485 | 0 | sequence_length = octet_string_length; |
2486 | |
|
2487 | 0 | if ((value_ptr = asn_parse_sequence(parse_ptr, &sequence_length, |
2488 | 0 | &type_value, |
2489 | 0 | (ASN_SEQUENCE | ASN_CONSTRUCTOR), |
2490 | 0 | "usm sequence")) == NULL) { |
2491 | | /* |
2492 | | * RETURN parse error |
2493 | 0 | */ return -1; |
2494 | 0 | } |
2495 | | |
2496 | | |
2497 | | /* |
2498 | | * Retrieve the engineID. |
2499 | | */ |
2500 | 0 | parse_ptr = value_ptr; |
2501 | 0 | remaining_bytes = sequence_length; |
2502 | |
|
2503 | 0 | DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineID"); |
2504 | 0 | if ((next_ptr |
2505 | 0 | = asn_parse_string(parse_ptr, &remaining_bytes, &type_value, |
2506 | 0 | secEngineID, secEngineIDLen)) == NULL) { |
2507 | 0 | DEBUGINDENTLESS(); |
2508 | | /* |
2509 | | * RETURN parse error |
2510 | 0 | */ return -1; |
2511 | 0 | } |
2512 | 0 | DEBUGINDENTLESS(); |
2513 | |
|
2514 | 0 | if (type_value != |
2515 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) { |
2516 | | /* |
2517 | | * RETURN parse error |
2518 | 0 | */ return -1; |
2519 | 0 | } |
2520 | | |
2521 | | |
2522 | | /* |
2523 | | * Retrieve the engine boots, notice switch in the way next_ptr and |
2524 | | * remaining_bytes are used (to accomodate the asn code). |
2525 | | */ |
2526 | 0 | DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineBoots"); |
2527 | 0 | if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value, |
2528 | 0 | &boots_long, sizeof(long))) == NULL) { |
2529 | 0 | DEBUGINDENTLESS(); |
2530 | | /* |
2531 | | * RETURN parse error |
2532 | 0 | */ return -1; |
2533 | 0 | } |
2534 | 0 | DEBUGINDENTLESS(); |
2535 | |
|
2536 | 0 | if (type_value != |
2537 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) { |
2538 | 0 | DEBUGINDENTLESS(); |
2539 | | /* |
2540 | | * RETURN parse error |
2541 | 0 | */ return -1; |
2542 | 0 | } |
2543 | | |
2544 | 0 | *boots_uint = (u_int) boots_long; |
2545 | | |
2546 | | |
2547 | | /* |
2548 | | * Retrieve the time value. |
2549 | | */ |
2550 | 0 | DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineTime"); |
2551 | 0 | if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value, |
2552 | 0 | &time_long, sizeof(long))) == NULL) { |
2553 | | /* |
2554 | | * RETURN parse error |
2555 | 0 | */ return -1; |
2556 | 0 | } |
2557 | 0 | DEBUGINDENTLESS(); |
2558 | |
|
2559 | 0 | if (type_value != |
2560 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) { |
2561 | | /* |
2562 | | * RETURN parse error |
2563 | 0 | */ return -1; |
2564 | 0 | } |
2565 | | |
2566 | 0 | *time_uint = (u_int) time_long; |
2567 | |
|
2568 | 0 | if (*boots_uint > ENGINEBOOT_MAX || *time_uint > ENGINETIME_MAX) { |
2569 | 0 | return -1; |
2570 | 0 | } |
2571 | | |
2572 | | /* |
2573 | | * Retrieve the secName. |
2574 | | */ |
2575 | 0 | origNameLen = *secNameLen; |
2576 | | |
2577 | |
|
2578 | 0 | DEBUGDUMPHEADER("recv", "msgUserName"); |
2579 | 0 | if ((next_ptr |
2580 | 0 | = asn_parse_string(next_ptr, &remaining_bytes, &type_value, |
2581 | 0 | (u_char *) secName, secNameLen)) == NULL) { |
2582 | 0 | DEBUGINDENTLESS(); |
2583 | | /* |
2584 | | * RETURN parse error |
2585 | 0 | */ return -1; |
2586 | 0 | } |
2587 | 0 | DEBUGINDENTLESS(); |
2588 | | |
2589 | | /* |
2590 | | * FIX -- doesn't this also indicate a buffer overrun? |
2591 | | */ |
2592 | 0 | if (origNameLen < *secNameLen + 1) { |
2593 | | /* |
2594 | | * RETURN parse error, but it's really a parameter error |
2595 | | */ |
2596 | 0 | return -1; |
2597 | 0 | } |
2598 | | |
2599 | 0 | if (*secNameLen > 32) { |
2600 | | /* |
2601 | | * This is a USM-specific limitation over and above the above |
2602 | | * limitation (which will probably default to the length of an |
2603 | | * SnmpAdminString, i.e. 255). See RFC 2574, sec. 2.4. |
2604 | | */ |
2605 | 0 | return -1; |
2606 | 0 | } |
2607 | | |
2608 | 0 | secName[*secNameLen] = '\0'; |
2609 | |
|
2610 | 0 | if (type_value != |
2611 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) { |
2612 | | /* |
2613 | | * RETURN parse error |
2614 | 0 | */ return -1; |
2615 | 0 | } |
2616 | | |
2617 | | |
2618 | | /* |
2619 | | * Retrieve the signature and blank it if there. |
2620 | | */ |
2621 | 0 | DEBUGDUMPHEADER("recv", "msgAuthenticationParameters"); |
2622 | 0 | if ((next_ptr |
2623 | 0 | = asn_parse_string(next_ptr, &remaining_bytes, &type_value, |
2624 | 0 | signature, signature_length)) == NULL) { |
2625 | 0 | DEBUGINDENTLESS(); |
2626 | | /* |
2627 | | * RETURN parse error |
2628 | 0 | */ return -1; |
2629 | 0 | } |
2630 | 0 | DEBUGINDENTLESS(); |
2631 | |
|
2632 | 0 | if (type_value != |
2633 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) { |
2634 | | /* |
2635 | | * RETURN parse error |
2636 | 0 | */ return -1; |
2637 | 0 | } |
2638 | | |
2639 | 0 | if (*signature_length != 0) { /* Blanking for authentication step later */ |
2640 | 0 | memset(next_ptr - (u_long) * signature_length, |
2641 | 0 | 0, *signature_length); |
2642 | 0 | } |
2643 | | |
2644 | | |
2645 | | /* |
2646 | | * Retrieve the salt. |
2647 | | * |
2648 | | * Note that the next ptr is where the data section starts. |
2649 | | */ |
2650 | 0 | DEBUGDUMPHEADER("recv", "msgPrivacyParameters"); |
2651 | 0 | if ((*data_ptr |
2652 | 0 | = asn_parse_string(next_ptr, &remaining_bytes, &type_value, |
2653 | 0 | salt, salt_length)) == NULL) { |
2654 | 0 | DEBUGINDENTLESS(); |
2655 | | /* |
2656 | | * RETURN parse error |
2657 | 0 | */ return -2; |
2658 | 0 | } |
2659 | 0 | DEBUGINDENTLESS(); |
2660 | |
|
2661 | 0 | if (type_value != |
2662 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) { |
2663 | | /* |
2664 | | * RETURN parse error |
2665 | 0 | */ return -2; |
2666 | 0 | } |
2667 | | |
2668 | 0 | return 0; |
2669 | |
|
2670 | 0 | } /* end usm_parse_security_parameters() */ |
2671 | | |
2672 | | |
2673 | | |
2674 | | |
2675 | | /*******************************************************************-o-****** |
2676 | | * usm_check_and_update_timeliness |
2677 | | * |
2678 | | * Parameters: |
2679 | | * *secEngineID |
2680 | | * secEngineIDen |
2681 | | * boots_uint |
2682 | | * time_uint |
2683 | | * *error |
2684 | | * |
2685 | | * Returns: |
2686 | | * 0 On success, |
2687 | | * -1 Otherwise. |
2688 | | * |
2689 | | * |
2690 | | * Performs the incoming timeliness checking and setting. |
2691 | | */ |
2692 | | static int |
2693 | | usm_check_and_update_timeliness(u_char * secEngineID, |
2694 | | size_t secEngineIDLen, |
2695 | | u_int boots_uint, |
2696 | | u_int time_uint, int *error) |
2697 | 0 | { |
2698 | 0 | u_char myID[USM_MAX_ID_LENGTH]; |
2699 | 0 | u_long myIDLength = |
2700 | 0 | snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH); |
2701 | 0 | u_int myBoots; |
2702 | 0 | u_int myTime; |
2703 | | |
2704 | | |
2705 | |
|
2706 | 0 | if ((myIDLength > USM_MAX_ID_LENGTH) || (myIDLength == 0)) { |
2707 | | /* |
2708 | | * We're probably already screwed...buffer overwrite. XXX? |
2709 | | */ |
2710 | 0 | DEBUGMSGTL(("usm", "Buffer overflow.\n")); |
2711 | 0 | *error = SNMPERR_USM_GENERICERROR; |
2712 | 0 | return -1; |
2713 | 0 | } |
2714 | | |
2715 | 0 | myBoots = snmpv3_local_snmpEngineBoots(); |
2716 | 0 | myTime = snmpv3_local_snmpEngineTime(); |
2717 | | |
2718 | | |
2719 | | /* |
2720 | | * IF the time involved is local |
2721 | | * Make sure message is inside the time window |
2722 | | * ELSE |
2723 | | * IF boots is higher or boots is the same and time is higher |
2724 | | * remember this new data |
2725 | | * ELSE |
2726 | | * IF !(boots same and time within USM_TIME_WINDOW secs) |
2727 | | * Message is too old |
2728 | | * ELSE |
2729 | | * Message is ok, but don't take time |
2730 | | * ENDIF |
2731 | | * ENDIF |
2732 | | * ENDIF |
2733 | | */ |
2734 | | |
2735 | | /* |
2736 | | * This is a local reference. |
2737 | | */ |
2738 | 0 | if (secEngineIDLen == myIDLength |
2739 | 0 | && memcmp(secEngineID, myID, myIDLength) == 0) { |
2740 | 0 | u_int time_difference = myTime > time_uint ? |
2741 | 0 | myTime - time_uint : time_uint - myTime; |
2742 | |
|
2743 | 0 | if (boots_uint == ENGINEBOOT_MAX |
2744 | 0 | || boots_uint != myBoots |
2745 | 0 | || time_difference > USM_TIME_WINDOW) { |
2746 | 0 | snmp_increment_statistic(STAT_USMSTATSNOTINTIMEWINDOWS); |
2747 | |
|
2748 | 0 | DEBUGMSGTL(("usm", |
2749 | 0 | "boot_uint %u myBoots %u time_diff %u => not in time window\n", |
2750 | 0 | boots_uint, myBoots, time_difference)); |
2751 | 0 | *error = SNMPERR_USM_NOTINTIMEWINDOW; |
2752 | 0 | return -1; |
2753 | 0 | } |
2754 | | |
2755 | 0 | *error = SNMPERR_SUCCESS; |
2756 | 0 | return 0; |
2757 | 0 | } |
2758 | | |
2759 | | /* |
2760 | | * This is a remote reference. |
2761 | | */ |
2762 | 0 | else { |
2763 | 0 | u_int theirBoots, theirTime, theirLastTime; |
2764 | 0 | u_int time_difference; |
2765 | |
|
2766 | 0 | if (get_enginetime_ex(secEngineID, secEngineIDLen, |
2767 | 0 | &theirBoots, &theirTime, |
2768 | 0 | &theirLastTime, TRUE) |
2769 | 0 | != SNMPERR_SUCCESS) { |
2770 | 0 | DEBUGMSGTL(("usm", "%s\n", |
2771 | 0 | "Failed to get remote engine's times.")); |
2772 | |
|
2773 | 0 | *error = SNMPERR_USM_GENERICERROR; |
2774 | 0 | return -1; |
2775 | 0 | } |
2776 | | |
2777 | 0 | time_difference = theirTime > time_uint ? |
2778 | 0 | theirTime - time_uint : time_uint - theirTime; |
2779 | | |
2780 | | |
2781 | | /* |
2782 | | * XXX Contrary to the pseudocode: |
2783 | | * See if boots is invalid first. |
2784 | | */ |
2785 | 0 | if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint) { |
2786 | 0 | DEBUGMSGTL(("usm", "%s\n", "Remote boot count invalid.")); |
2787 | |
|
2788 | 0 | *error = SNMPERR_USM_NOTINTIMEWINDOW; |
2789 | 0 | return -1; |
2790 | 0 | } |
2791 | | |
2792 | | |
2793 | | /* |
2794 | | * Boots is ok, see if the boots is the same but the time |
2795 | | * is old. |
2796 | | */ |
2797 | 0 | if (theirBoots == boots_uint && time_uint < theirLastTime) { |
2798 | 0 | if (time_difference > USM_TIME_WINDOW) { |
2799 | 0 | DEBUGMSGTL(("usm", "%s\n", "Message too old.")); |
2800 | 0 | *error = SNMPERR_USM_NOTINTIMEWINDOW; |
2801 | 0 | return -1; |
2802 | 0 | } |
2803 | | |
2804 | 0 | else { /* Old, but acceptable */ |
2805 | |
|
2806 | 0 | *error = SNMPERR_SUCCESS; |
2807 | 0 | return 0; |
2808 | 0 | } |
2809 | 0 | } |
2810 | | |
2811 | | |
2812 | | /* |
2813 | | * Message is ok, either boots has been advanced, or |
2814 | | * time is greater than before with the same boots. |
2815 | | */ |
2816 | | |
2817 | 0 | if (set_enginetime(secEngineID, secEngineIDLen, |
2818 | 0 | boots_uint, time_uint, TRUE) |
2819 | 0 | != SNMPERR_SUCCESS) { |
2820 | 0 | DEBUGMSGTL(("usm", "%s\n", |
2821 | 0 | "Failed updating remote boot/time.")); |
2822 | 0 | *error = SNMPERR_USM_GENERICERROR; |
2823 | 0 | return -1; |
2824 | 0 | } |
2825 | | |
2826 | 0 | *error = SNMPERR_SUCCESS; |
2827 | 0 | return 0; /* Fresh message and time updated */ |
2828 | |
|
2829 | 0 | } /* endif -- local or remote time reference. */ |
2830 | | |
2831 | |
|
2832 | 0 | } /* end usm_check_and_update_timeliness() */ |
2833 | | |
2834 | | /*******************************************************************-o-****** |
2835 | | * usm_check_secLevel |
2836 | | * |
2837 | | * Parameters: |
2838 | | * level |
2839 | | * *user |
2840 | | * |
2841 | | * Returns: |
2842 | | * 0 On success, |
2843 | | * -1 Otherwise. |
2844 | | * |
2845 | | * Checks that a given security level is valid for a given user. |
2846 | | */ |
2847 | | static int |
2848 | | usm_check_secLevel(int level, struct usmUser *user) |
2849 | 0 | { |
2850 | |
|
2851 | 0 | if (user->userStatus != RS_ACTIVE) |
2852 | 0 | return -1; |
2853 | | |
2854 | 0 | DEBUGMSGTL(("comparex", "Comparing: %" NETSNMP_PRIo "u %" NETSNMP_PRIo "u ", |
2855 | 0 | usmNoPrivProtocol[0], usmNoPrivProtocol[1])); |
2856 | 0 | DEBUGMSGOID(("comparex", usmNoPrivProtocol, |
2857 | 0 | OID_LENGTH(usmNoPrivProtocol))); |
2858 | 0 | DEBUGMSG(("comparex", "\n")); |
2859 | 0 | if (level == SNMP_SEC_LEVEL_AUTHPRIV |
2860 | 0 | && (netsnmp_oid_equals(user->privProtocol, user->privProtocolLen, |
2861 | 0 | usmNoPrivProtocol, |
2862 | 0 | OID_LENGTH(usmNoPrivProtocol)) == |
2863 | 0 | 0)) { |
2864 | 0 | DEBUGMSGTL(("usm", "Level: %d\n", level)); |
2865 | 0 | DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name)); |
2866 | 0 | DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen)); |
2867 | 0 | DEBUGMSG(("usm", ", User Priv Protocol: ")); |
2868 | 0 | DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen)); |
2869 | 0 | DEBUGMSG(("usm", "\n")); |
2870 | 0 | return 1; |
2871 | 0 | } |
2872 | 0 | if ((level == SNMP_SEC_LEVEL_AUTHPRIV |
2873 | 0 | || level == SNMP_SEC_LEVEL_AUTHNOPRIV) |
2874 | 0 | && |
2875 | 0 | (netsnmp_oid_equals |
2876 | 0 | (user->authProtocol, user->authProtocolLen, usmNoAuthProtocol, |
2877 | 0 | OID_LENGTH(usmNoAuthProtocol)) == 0)) { |
2878 | 0 | DEBUGMSGTL(("usm", "Level: %d\n", level)); |
2879 | 0 | DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name)); |
2880 | 0 | DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen)); |
2881 | 0 | DEBUGMSG(("usm", ", User Priv Protocol: ")); |
2882 | 0 | DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen)); |
2883 | 0 | DEBUGMSG(("usm", "\n")); |
2884 | 0 | return 1; |
2885 | 0 | } |
2886 | | |
2887 | 0 | return 0; |
2888 | 0 | } /* end usm_check_secLevel() */ |
2889 | | |
2890 | | /*******************************************************************-o-****** |
2891 | | * usm_process_in_msg |
2892 | | * |
2893 | | * Parameters: |
2894 | | * (See list below...) |
2895 | | * |
2896 | | * Returns: |
2897 | | * SNMPERR_SUCCESS On success. |
2898 | | * SNMPERR_USM_AUTHENTICATIONFAILURE |
2899 | | * SNMPERR_USM_DECRYPTIONERROR |
2900 | | * SNMPERR_USM_GENERICERROR |
2901 | | * SNMPERR_USM_PARSEERROR |
2902 | | * SNMPERR_USM_UNKNOWNENGINEID |
2903 | | * SNMPERR_USM_PARSEERROR |
2904 | | * SNMPERR_USM_UNKNOWNSECURITYNAME |
2905 | | * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL |
2906 | | * |
2907 | | * |
2908 | | * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU. |
2909 | | */ |
2910 | | static int |
2911 | | usm_process_in_msg(int msgProcModel, /* (UNUSED) */ |
2912 | | size_t maxMsgSize, /* IN - Used to calc maxSizeResponse. */ |
2913 | | u_char * secParams, /* IN - BER encoded securityParameters. */ |
2914 | | int secModel, /* (UNUSED) */ |
2915 | | int secLevel, /* IN - AuthNoPriv, authPriv etc. */ |
2916 | | u_char * wholeMsg, /* IN - Original v3 message. */ |
2917 | | size_t wholeMsgLen, /* IN - Msg length. */ |
2918 | | u_char * secEngineID, /* OUT - Pointer snmpEngineID. */ |
2919 | | size_t * secEngineIDLen, /* IN/OUT - Len available, len returned. */ |
2920 | | /* |
2921 | | * NOTE: Memory provided by caller. |
2922 | | */ |
2923 | | char *secName, /* OUT - Pointer to securityName. */ |
2924 | | size_t * secNameLen, /* IN/OUT - Len available, len returned. */ |
2925 | | u_char ** scopedPdu, /* OUT - Pointer to plaintext scopedPdu. */ |
2926 | | size_t * scopedPduLen, /* IN/OUT - Len available, len returned. */ |
2927 | | size_t * maxSizeResponse, /* OUT - Max size of Response PDU. */ |
2928 | | void **secStateRf, /* OUT - Ref to security state. */ |
2929 | | netsnmp_session * sess, /* IN - session which got the message */ |
2930 | | u_char msg_flags) |
2931 | 0 | { /* IN - v3 Message flags. */ |
2932 | 0 | size_t remaining = wholeMsgLen - (u_int) |
2933 | 0 | ((u_long) * secParams - (u_long) * wholeMsg); |
2934 | 0 | u_int boots_uint; |
2935 | 0 | u_int time_uint; |
2936 | 0 | #ifdef HAVE_AES |
2937 | 0 | u_int net_boots, net_time; |
2938 | 0 | #endif |
2939 | 0 | #ifndef NETSNMP_DISABLE_DES |
2940 | 0 | int i; |
2941 | 0 | #endif |
2942 | 0 | u_char signature[USM_MAX_AUTHSIZE]; |
2943 | 0 | size_t signature_length = USM_MAX_AUTHSIZE; |
2944 | 0 | u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)]; |
2945 | 0 | size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH); |
2946 | 0 | u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)]; |
2947 | 0 | u_int iv_length = BYTESIZE(USM_MAX_SALT_LENGTH); |
2948 | 0 | u_char *data_ptr; |
2949 | 0 | u_char *value_ptr; |
2950 | 0 | u_char type_value; |
2951 | 0 | u_char *end_of_overhead = NULL; |
2952 | 0 | int error; |
2953 | 0 | int rc = 0; |
2954 | 0 | struct usmStateReference **secStateRef = |
2955 | 0 | (struct usmStateReference **) secStateRf; |
2956 | |
|
2957 | 0 | struct usmUser *user; |
2958 | | |
2959 | |
|
2960 | 0 | DEBUGMSGTL(("usm", "USM processing begun...\n")); |
2961 | |
|
2962 | 0 | netsnmp_assert(secStateRef); |
2963 | |
|
2964 | 0 | usm_free_usmStateReference(*secStateRef); |
2965 | 0 | *secStateRef = usm_malloc_usmStateReference(); |
2966 | 0 | if (*secStateRef == NULL) { |
2967 | 0 | DEBUGMSGTL(("usm", "Out of memory.\n")); |
2968 | 0 | return SNMPERR_USM_GENERICERROR; |
2969 | 0 | } |
2970 | | |
2971 | | /* |
2972 | | * Make sure the *secParms is an OCTET STRING. |
2973 | | * Extract the user name, engine ID, and security level. |
2974 | | */ |
2975 | 0 | if ((rc = usm_parse_security_parameters(secParams, remaining, |
2976 | 0 | secEngineID, secEngineIDLen, |
2977 | 0 | &boots_uint, &time_uint, |
2978 | 0 | secName, secNameLen, |
2979 | 0 | signature, &signature_length, |
2980 | 0 | salt, &salt_length, |
2981 | 0 | &data_ptr)) < 0) { |
2982 | 0 | DEBUGMSGTL(("usm", "Parsing failed (rc %d).\n", rc)); |
2983 | 0 | if (rc == -2) { |
2984 | | /* |
2985 | | * This indicates a decryptionError. |
2986 | | */ |
2987 | 0 | snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS); |
2988 | 0 | error = SNMPERR_USM_DECRYPTIONERROR; |
2989 | 0 | } else { |
2990 | 0 | snmp_increment_statistic(STAT_SNMPINASNPARSEERRS); |
2991 | 0 | error = SNMPERR_USM_PARSEERROR; |
2992 | 0 | } |
2993 | 0 | goto err; |
2994 | 0 | } |
2995 | | |
2996 | | /* |
2997 | | * RFC 2574 section 8.3.2 |
2998 | | * 1) If the privParameters field is not an 8-octet OCTET STRING, |
2999 | | * then an error indication (decryptionError) is returned to the |
3000 | | * calling module. |
3001 | | */ |
3002 | 0 | if ((secLevel == SNMP_SEC_LEVEL_AUTHPRIV) && (salt_length != 8)) { |
3003 | 0 | snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS); |
3004 | 0 | error = SNMPERR_USM_DECRYPTIONERROR; |
3005 | 0 | goto err; |
3006 | 0 | } |
3007 | | |
3008 | 0 | if (secLevel != SNMP_SEC_LEVEL_AUTHPRIV) { |
3009 | | /* |
3010 | | * pull these out now so reports can use them |
3011 | | */ |
3012 | 0 | *scopedPdu = data_ptr; |
3013 | 0 | *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg); |
3014 | 0 | end_of_overhead = data_ptr; |
3015 | 0 | } |
3016 | | |
3017 | | /* |
3018 | | * Cache the name, engine ID, and security level, |
3019 | | * * per step 2 (section 3.2) |
3020 | | */ |
3021 | 0 | if (usm_set_usmStateReference_name |
3022 | 0 | (*secStateRef, secName, *secNameLen) == -1) { |
3023 | 0 | DEBUGMSGTL(("usm", "%s\n", "Couldn't cache name.")); |
3024 | 0 | error = SNMPERR_USM_GENERICERROR; |
3025 | 0 | goto err; |
3026 | 0 | } |
3027 | | |
3028 | 0 | if (usm_set_usmStateReference_engine_id |
3029 | 0 | (*secStateRef, secEngineID, *secEngineIDLen) == -1) { |
3030 | 0 | DEBUGMSGTL(("usm", "%s\n", "Couldn't cache engine id.")); |
3031 | 0 | error = SNMPERR_USM_GENERICERROR; |
3032 | 0 | goto err; |
3033 | 0 | } |
3034 | | |
3035 | 0 | if (usm_set_usmStateReference_sec_level(*secStateRef, secLevel) == |
3036 | 0 | -1) { |
3037 | 0 | DEBUGMSGTL(("usm", "%s\n", "Couldn't cache security level.")); |
3038 | 0 | error = SNMPERR_USM_GENERICERROR; |
3039 | 0 | goto err; |
3040 | 0 | } |
3041 | | |
3042 | | /* |
3043 | | * Locate the engine ID record. |
3044 | | * If it is unknown, then either create one or note this as an error. |
3045 | | */ |
3046 | 0 | if ((sess && (sess->isAuthoritative == SNMP_SESS_AUTHORITATIVE || |
3047 | 0 | (sess->isAuthoritative == SNMP_SESS_UNKNOWNAUTH && |
3048 | 0 | (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)))) || |
3049 | 0 | (!sess && (msg_flags & SNMP_MSG_FLAG_RPRT_BIT))) { |
3050 | 0 | if (ISENGINEKNOWN(secEngineID, *secEngineIDLen) == FALSE) { |
3051 | 0 | DEBUGMSGTL(("usm", "Unknown Engine ID.\n")); |
3052 | 0 | snmp_increment_statistic(STAT_USMSTATSUNKNOWNENGINEIDS); |
3053 | 0 | error = SNMPERR_USM_UNKNOWNENGINEID; |
3054 | 0 | goto err; |
3055 | 0 | } |
3056 | 0 | } else { |
3057 | 0 | if (ENSURE_ENGINE_RECORD(secEngineID, *secEngineIDLen) |
3058 | 0 | != SNMPERR_SUCCESS) { |
3059 | 0 | DEBUGMSGTL(("usm", "%s\n", "Couldn't ensure engine record.")); |
3060 | 0 | error = SNMPERR_USM_GENERICERROR; |
3061 | 0 | goto err; |
3062 | 0 | } |
3063 | |
|
3064 | 0 | } |
3065 | | |
3066 | | |
3067 | | /* |
3068 | | * Locate the User record. |
3069 | | * If the user/engine ID is unknown, report this as an error. |
3070 | | */ |
3071 | 0 | if ((user = usm_get_user_from_list(secEngineID, *secEngineIDLen, |
3072 | 0 | secName, *secNameLen, userList, |
3073 | 0 | (((sess && sess->isAuthoritative == |
3074 | 0 | SNMP_SESS_AUTHORITATIVE) || |
3075 | 0 | (!sess)) ? 0 : 1))) |
3076 | 0 | == NULL) { |
3077 | 0 | DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName)); |
3078 | 0 | snmp_increment_statistic(STAT_USMSTATSUNKNOWNUSERNAMES); |
3079 | 0 | error = SNMPERR_USM_UNKNOWNSECURITYNAME; |
3080 | 0 | goto err; |
3081 | 0 | } |
3082 | | |
3083 | | /* ensure the user is active */ |
3084 | 0 | if (user->userStatus != RS_ACTIVE) { |
3085 | 0 | DEBUGMSGTL(("usm", "Attempt to use an inactive user.\n")); |
3086 | 0 | error = SNMPERR_USM_UNKNOWNSECURITYNAME; |
3087 | 0 | goto err; |
3088 | 0 | } |
3089 | | |
3090 | | /* |
3091 | | * Make sure the security level is appropriate. |
3092 | | */ |
3093 | | |
3094 | 0 | rc = usm_check_secLevel(secLevel, user); |
3095 | 0 | if (1 == rc) { |
3096 | 0 | DEBUGMSGTL(("usm", "Unsupported Security Level (%d).\n", |
3097 | 0 | secLevel)); |
3098 | 0 | snmp_increment_statistic(STAT_USMSTATSUNSUPPORTEDSECLEVELS); |
3099 | 0 | error = SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL; |
3100 | 0 | goto err; |
3101 | 0 | } else if (rc != 0) { |
3102 | 0 | DEBUGMSGTL(("usm", "Unknown issue.\n")); |
3103 | 0 | error = SNMPERR_USM_GENERICERROR; |
3104 | 0 | goto err; |
3105 | 0 | } |
3106 | | |
3107 | | /* |
3108 | | * Check the authentication credentials of the message. |
3109 | | */ |
3110 | 0 | if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV |
3111 | 0 | || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
3112 | 0 | if (sc_check_keyed_hash(user->authProtocol, user->authProtocolLen, |
3113 | 0 | user->authKey, user->authKeyLen, |
3114 | 0 | wholeMsg, wholeMsgLen, |
3115 | 0 | signature, signature_length) |
3116 | 0 | != SNMP_ERR_NOERROR) { |
3117 | 0 | DEBUGMSGTL(("usm", "Verification failed.\n")); |
3118 | 0 | snmp_increment_statistic(STAT_USMSTATSWRONGDIGESTS); |
3119 | 0 | snmp_log(LOG_WARNING, "Authentication failed for %s\n", |
3120 | 0 | user->name); |
3121 | 0 | error = SNMPERR_USM_AUTHENTICATIONFAILURE; |
3122 | 0 | goto err; |
3123 | 0 | } |
3124 | | |
3125 | 0 | DEBUGMSGTL(("usm", "Verification succeeded.\n")); |
3126 | 0 | } |
3127 | | |
3128 | | |
3129 | | /* |
3130 | | * Steps 10-11 user is already set - relocated before timeliness |
3131 | | * check in case it fails - still save user data for response. |
3132 | | * |
3133 | | * Cache the keys and protocol oids, per step 11 (s3.2). |
3134 | | */ |
3135 | 0 | if (usm_set_usmStateReference_auth_protocol(*secStateRef, |
3136 | 0 | user->authProtocol, |
3137 | 0 | user-> |
3138 | 0 | authProtocolLen) == -1) { |
3139 | 0 | DEBUGMSGTL(("usm", "%s\n", |
3140 | 0 | "Couldn't cache authentication protocol.")); |
3141 | 0 | error = SNMPERR_USM_GENERICERROR; |
3142 | 0 | goto err; |
3143 | 0 | } |
3144 | | |
3145 | 0 | if (usm_set_usmStateReference_auth_key(*secStateRef, |
3146 | 0 | user->authKey, |
3147 | 0 | user->authKeyLen) == -1) { |
3148 | 0 | DEBUGMSGTL(("usm", "%s\n", |
3149 | 0 | "Couldn't cache authentication key.")); |
3150 | 0 | error = SNMPERR_USM_GENERICERROR; |
3151 | 0 | goto err; |
3152 | 0 | } |
3153 | | |
3154 | 0 | if (usm_set_usmStateReference_priv_protocol(*secStateRef, |
3155 | 0 | user->privProtocol, |
3156 | 0 | user-> |
3157 | 0 | privProtocolLen) == -1) { |
3158 | 0 | DEBUGMSGTL(("usm", "%s\n", |
3159 | 0 | "Couldn't cache privacy protocol.")); |
3160 | 0 | error = SNMPERR_USM_GENERICERROR; |
3161 | 0 | goto err; |
3162 | 0 | } |
3163 | | |
3164 | 0 | if (usm_set_usmStateReference_priv_key(*secStateRef, |
3165 | 0 | user->privKey, |
3166 | 0 | user->privKeyLen) == -1) { |
3167 | 0 | DEBUGMSGTL(("usm", "%s\n", "Couldn't cache privacy key.")); |
3168 | 0 | error = SNMPERR_USM_GENERICERROR; |
3169 | 0 | goto err; |
3170 | 0 | } |
3171 | | |
3172 | | |
3173 | | /* |
3174 | | * Perform the timeliness/time manager functions. |
3175 | | */ |
3176 | 0 | if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV |
3177 | 0 | || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
3178 | 0 | if (usm_check_and_update_timeliness(secEngineID, *secEngineIDLen, |
3179 | 0 | boots_uint, time_uint, |
3180 | 0 | &error) == -1) { |
3181 | 0 | goto err; |
3182 | 0 | } |
3183 | 0 | } |
3184 | 0 | #ifdef LCD_TIME_SYNC_OPT |
3185 | | /* |
3186 | | * Cache the unauthenticated time to use in case we don't have |
3187 | | * anything better - this guess will be no worse than (0,0) |
3188 | | * that we normally use. |
3189 | | */ |
3190 | 0 | else { |
3191 | 0 | set_enginetime(secEngineID, *secEngineIDLen, |
3192 | 0 | boots_uint, time_uint, FALSE); |
3193 | 0 | } |
3194 | 0 | #endif /* LCD_TIME_SYNC_OPT */ |
3195 | | |
3196 | | |
3197 | | /* |
3198 | | * If needed, decrypt the scoped PDU. |
3199 | | */ |
3200 | 0 | if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { |
3201 | 0 | int priv_type = sc_get_privtype(user->privProtocol, |
3202 | 0 | user->privProtocolLen); |
3203 | 0 | remaining = wholeMsgLen - (data_ptr - wholeMsg); |
3204 | |
|
3205 | 0 | if ((value_ptr = asn_parse_sequence(data_ptr, &remaining, |
3206 | 0 | &type_value, |
3207 | 0 | (ASN_UNIVERSAL | ASN_PRIMITIVE |
3208 | 0 | | ASN_OCTET_STR), |
3209 | 0 | "encrypted sPDU")) == NULL) { |
3210 | 0 | DEBUGMSGTL(("usm", "%s\n", |
3211 | 0 | "Failed while parsing encrypted sPDU.")); |
3212 | 0 | snmp_increment_statistic(STAT_SNMPINASNPARSEERRS); |
3213 | 0 | usm_free_usmStateReference(*secStateRef); |
3214 | 0 | *secStateRef = NULL; |
3215 | 0 | error = SNMPERR_USM_PARSEERROR; |
3216 | 0 | goto err; |
3217 | 0 | } |
3218 | | |
3219 | 0 | #ifndef NETSNMP_DISABLE_DES |
3220 | 0 | if (USM_CREATE_USER_PRIV_DES == (priv_type & USM_PRIV_MASK_ALG)) { |
3221 | | /* |
3222 | | * From RFC2574: |
3223 | | * |
3224 | | * "Before decryption, the encrypted data length is verified. |
3225 | | * If the length of the OCTET STRING to be decrypted is not |
3226 | | * an integral multiple of 8 octets, the decryption process |
3227 | | * is halted and an appropriate exception noted." |
3228 | | */ |
3229 | |
|
3230 | 0 | if (remaining % 8 != 0) { |
3231 | 0 | DEBUGMSGTL(("usm", |
3232 | 0 | "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %lu)\n", |
3233 | 0 | (unsigned long)remaining, (unsigned long)remaining % 8)); |
3234 | 0 | snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS); |
3235 | 0 | usm_free_usmStateReference(*secStateRef); |
3236 | 0 | *secStateRef = NULL; |
3237 | 0 | error = SNMPERR_USM_DECRYPTIONERROR; |
3238 | 0 | goto err; |
3239 | 0 | } |
3240 | | |
3241 | 0 | end_of_overhead = value_ptr; |
3242 | |
|
3243 | 0 | if ( !user->privKey ) { |
3244 | 0 | DEBUGMSGTL(("usm", "No privacy pass phrase for %s\n", user->secName)); |
3245 | 0 | snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS); |
3246 | 0 | usm_free_usmStateReference(*secStateRef); |
3247 | 0 | *secStateRef = NULL; |
3248 | 0 | error = SNMPERR_USM_DECRYPTIONERROR; |
3249 | 0 | goto err; |
3250 | 0 | } |
3251 | | |
3252 | | /* |
3253 | | * XOR the salt with the last (iv_length) bytes |
3254 | | * of the priv_key to obtain the IV. |
3255 | | */ |
3256 | 0 | iv_length = BYTESIZE(USM_DES_SALT_LENGTH); |
3257 | 0 | for (i = 0; i < (int) iv_length; i++) |
3258 | 0 | iv[i] = salt[i] ^ user->privKey[iv_length + i]; |
3259 | 0 | } |
3260 | 0 | #endif |
3261 | 0 | #ifdef HAVE_AES |
3262 | 0 | if (USM_CREATE_USER_PRIV_AES == (priv_type & USM_PRIV_MASK_ALG)) { |
3263 | 0 | iv_length = BYTESIZE(USM_AES_SALT_LENGTH); |
3264 | 0 | net_boots = ntohl(boots_uint); |
3265 | 0 | net_time = ntohl(time_uint); |
3266 | 0 | memcpy(iv, &net_boots, 4); |
3267 | 0 | memcpy(iv+4, &net_time, 4); |
3268 | 0 | memcpy(iv+8, salt, salt_length); |
3269 | 0 | } |
3270 | 0 | #endif |
3271 | |
|
3272 | | #ifdef NETSNMP_ENABLE_TESTING_CODE |
3273 | | if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { |
3274 | | dump_chunk("usm/dump", "Cypher Text", value_ptr, remaining); |
3275 | | dump_chunk("usm/dump", "salt + Encrypted form:", |
3276 | | salt, salt_length); |
3277 | | dump_chunk("usm/dump", "IV + Encrypted form:", iv, iv_length); |
3278 | | } |
3279 | | #endif |
3280 | 0 | if (sc_decrypt(user->privProtocol, user->privProtocolLen, |
3281 | 0 | user->privKey, user->privKeyLen, |
3282 | 0 | iv, iv_length, |
3283 | 0 | value_ptr, remaining, *scopedPdu, scopedPduLen) |
3284 | 0 | != SNMP_ERR_NOERROR) { |
3285 | 0 | DEBUGMSGTL(("usm", "%s\n", "Failed decryption.")); |
3286 | 0 | snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS); |
3287 | 0 | error = SNMPERR_USM_DECRYPTIONERROR; |
3288 | 0 | goto err; |
3289 | 0 | } |
3290 | | #ifdef NETSNMP_ENABLE_TESTING_CODE |
3291 | | if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { |
3292 | | dump_chunk("usm/dump", "Decrypted chunk:", |
3293 | | *scopedPdu, *scopedPduLen); |
3294 | | } |
3295 | | #endif |
3296 | 0 | } |
3297 | | /* |
3298 | | * sPDU is plaintext. |
3299 | | */ |
3300 | 0 | else { |
3301 | 0 | *scopedPdu = data_ptr; |
3302 | 0 | *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg); |
3303 | 0 | end_of_overhead = data_ptr; |
3304 | |
|
3305 | 0 | } /* endif -- PDU decryption */ |
3306 | | |
3307 | | |
3308 | | /* |
3309 | | * Calculate the biggest sPDU for the response (i.e., whole - ovrhd). |
3310 | | * |
3311 | | * FIX Correct? |
3312 | | */ |
3313 | 0 | *maxSizeResponse = maxMsgSize - (end_of_overhead - wholeMsg); |
3314 | | |
3315 | |
|
3316 | 0 | DEBUGMSGTL(("usm", "USM processing completed.\n")); |
3317 | |
|
3318 | 0 | return SNMPERR_SUCCESS; |
3319 | | |
3320 | 0 | err: |
3321 | 0 | usm_free_usmStateReference(*secStateRef); |
3322 | 0 | *secStateRef = NULL; |
3323 | 0 | netsnmp_assert(error != SNMPERR_SUCCESS); |
3324 | 0 | return error; |
3325 | 0 | } /* end usm_process_in_msg() */ |
3326 | | |
3327 | | static int |
3328 | | usm_secmod_process_in_msg(struct snmp_secmod_incoming_params *parms) |
3329 | 0 | { |
3330 | 0 | if (!parms) |
3331 | 0 | return SNMPERR_GENERR; |
3332 | | |
3333 | 0 | return usm_process_in_msg(parms->msgProcModel, |
3334 | 0 | parms->maxMsgSize, |
3335 | 0 | parms->secParams, |
3336 | 0 | parms->secModel, |
3337 | 0 | parms->secLevel, |
3338 | 0 | parms->wholeMsg, |
3339 | 0 | parms->wholeMsgLen, |
3340 | 0 | parms->secEngineID, |
3341 | 0 | parms->secEngineIDLen, |
3342 | 0 | parms->secName, |
3343 | 0 | parms->secNameLen, |
3344 | 0 | parms->scopedPdu, |
3345 | 0 | parms->scopedPduLen, |
3346 | 0 | parms->maxSizeResponse, |
3347 | 0 | parms->secStateRef, |
3348 | 0 | parms->sess, parms->msg_flags); |
3349 | 0 | } |
3350 | | |
3351 | | static void |
3352 | | usm_handle_report(struct session_list *slp, |
3353 | | netsnmp_transport *transport, netsnmp_session *session, |
3354 | | int result, netsnmp_pdu *pdu) |
3355 | 0 | { |
3356 | | /* |
3357 | | * handle reportable errors |
3358 | | */ |
3359 | | |
3360 | | /* this will get in our way */ |
3361 | 0 | usm_free_usmStateReference(pdu->securityStateRef); |
3362 | 0 | pdu->securityStateRef = NULL; |
3363 | |
|
3364 | 0 | switch (result) { |
3365 | 0 | case SNMPERR_USM_AUTHENTICATIONFAILURE: |
3366 | 0 | { |
3367 | 0 | int res = session->s_snmp_errno; |
3368 | 0 | session->s_snmp_errno = result; |
3369 | 0 | if (session->callback) { |
3370 | 0 | session->callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE, |
3371 | 0 | session, pdu->reqid, pdu, |
3372 | 0 | session->callback_magic); |
3373 | 0 | } |
3374 | 0 | session->s_snmp_errno = res; |
3375 | 0 | } |
3376 | 0 | NETSNMP_FALLTHROUGH; |
3377 | 0 | case SNMPERR_USM_UNKNOWNENGINEID: |
3378 | 0 | case SNMPERR_USM_UNKNOWNSECURITYNAME: |
3379 | 0 | case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL: |
3380 | 0 | case SNMPERR_USM_NOTINTIMEWINDOW: |
3381 | 0 | case SNMPERR_USM_DECRYPTIONERROR: |
3382 | |
|
3383 | 0 | if (SNMP_CMD_CONFIRMED(pdu->command) || |
3384 | 0 | (pdu->command == 0 |
3385 | 0 | && (pdu->flags & SNMP_MSG_FLAG_RPRT_BIT))) { |
3386 | 0 | netsnmp_pdu *pdu2; |
3387 | 0 | int flags = pdu->flags; |
3388 | |
|
3389 | 0 | pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY; |
3390 | 0 | pdu2 = snmp_clone_pdu(pdu); |
3391 | 0 | pdu->flags = pdu2->flags = flags; |
3392 | 0 | snmpv3_make_report(pdu2, result); |
3393 | 0 | if (0 == snmp_sess_send(slp, pdu2)) { |
3394 | 0 | snmp_free_pdu(pdu2); |
3395 | | /* |
3396 | | * TODO: indicate error |
3397 | | */ |
3398 | 0 | } |
3399 | 0 | } |
3400 | 0 | break; |
3401 | 0 | } |
3402 | 0 | } |
3403 | | |
3404 | | /** utility function to call netsnmp_extend_kul for a usmUser */ |
3405 | | int |
3406 | | usm_extend_user_kul(struct usmUser *user, u_int privKeyBufSize) |
3407 | 0 | { |
3408 | 0 | const netsnmp_priv_alg_info *pai; |
3409 | |
|
3410 | 0 | DEBUGMSGTL(("usm", "extending key\n")); |
3411 | |
|
3412 | 0 | if (NULL == user) { |
3413 | 0 | DEBUGMSGTL(("usm", "null user!\n")); |
3414 | 0 | return SNMPERR_GENERR; |
3415 | 0 | } |
3416 | | |
3417 | 0 | pai = sc_get_priv_alg_byoid(user->privProtocol, user->privProtocolLen); |
3418 | 0 | if (NULL == pai) { |
3419 | 0 | DEBUGMSGTL(("usm", "privProtocol lookup failed!\n")); |
3420 | 0 | return SNMPERR_GENERR; |
3421 | 0 | } |
3422 | | |
3423 | 0 | return netsnmp_extend_kul(pai->proper_length, user->authProtocol, |
3424 | 0 | user->authProtocolLen, pai->type, user->engineID, |
3425 | 0 | user->engineIDLen, &user->privKey, |
3426 | 0 | &user->privKeyLen, privKeyBufSize); |
3427 | 0 | } |
3428 | | |
3429 | | /* sets up initial default session parameters */ |
3430 | | static int |
3431 | | usm_session_init(netsnmp_session *in_session, netsnmp_session *session) |
3432 | 0 | { |
3433 | 0 | char *cp; |
3434 | 0 | size_t i; |
3435 | | |
3436 | 0 | if (in_session->securityAuthProtoLen > 0) { |
3437 | 0 | session->securityAuthProto = |
3438 | 0 | snmp_duplicate_objid(in_session->securityAuthProto, |
3439 | 0 | in_session->securityAuthProtoLen); |
3440 | 0 | if (session->securityAuthProto == NULL) { |
3441 | 0 | in_session->s_snmp_errno = SNMPERR_MALLOC; |
3442 | 0 | return SNMPERR_MALLOC; |
3443 | 0 | } |
3444 | 0 | } else if (get_default_authtype(&i) != NULL) { |
3445 | 0 | session->securityAuthProto = |
3446 | 0 | snmp_duplicate_objid(get_default_authtype(NULL), i); |
3447 | 0 | session->securityAuthProtoLen = i; |
3448 | 0 | } |
3449 | | |
3450 | 0 | if (in_session->securityPrivProtoLen > 0) { |
3451 | 0 | session->securityPrivProto = |
3452 | 0 | snmp_duplicate_objid(in_session->securityPrivProto, |
3453 | 0 | in_session->securityPrivProtoLen); |
3454 | 0 | if (session->securityPrivProto == NULL) { |
3455 | 0 | in_session->s_snmp_errno = SNMPERR_MALLOC; |
3456 | 0 | return SNMPERR_MALLOC; |
3457 | 0 | } |
3458 | 0 | } else if (get_default_privtype(&i) != NULL) { |
3459 | 0 | session->securityPrivProto = |
3460 | 0 | snmp_duplicate_objid(get_default_privtype(NULL), i); |
3461 | 0 | session->securityPrivProtoLen = i; |
3462 | 0 | } |
3463 | | |
3464 | 0 | if ((in_session->securityAuthKeyLen <= 0) && |
3465 | 0 | ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
3466 | 0 | NETSNMP_DS_LIB_AUTHMASTERKEY)))) { |
3467 | 0 | size_t buflen = sizeof(session->securityAuthKey); |
3468 | 0 | u_char *tmpp = session->securityAuthKey; |
3469 | 0 | session->securityAuthKeyLen = 0; |
3470 | | /* it will be a hex string */ |
3471 | 0 | if (!snmp_hex_to_binary(&tmpp, &buflen, |
3472 | 0 | &session->securityAuthKeyLen, 0, cp)) { |
3473 | 0 | snmp_set_detail("error parsing authentication master key"); |
3474 | 0 | return SNMP_ERR_GENERR; |
3475 | 0 | } |
3476 | 0 | } else if ((in_session->securityAuthKeyLen <= 0) && |
3477 | 0 | ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
3478 | 0 | NETSNMP_DS_LIB_AUTHPASSPHRASE)) || |
3479 | 0 | (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
3480 | 0 | NETSNMP_DS_LIB_PASSPHRASE)))) { |
3481 | 0 | session->securityAuthKeyLen = USM_AUTH_KU_LEN; |
3482 | 0 | if (generate_Ku(session->securityAuthProto, |
3483 | 0 | session->securityAuthProtoLen, |
3484 | 0 | (u_char *) cp, strlen(cp), |
3485 | 0 | session->securityAuthKey, |
3486 | 0 | &session->securityAuthKeyLen) != SNMPERR_SUCCESS) { |
3487 | 0 | snmp_set_detail |
3488 | 0 | ("Error generating a key (Ku) from the supplied authentication pass phrase."); |
3489 | 0 | return SNMP_ERR_GENERR; |
3490 | 0 | } |
3491 | 0 | } |
3492 | | |
3493 | | |
3494 | 0 | if ((in_session->securityPrivKeyLen <= 0) && |
3495 | 0 | ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
3496 | 0 | NETSNMP_DS_LIB_PRIVMASTERKEY)))) { |
3497 | 0 | size_t buflen = sizeof(session->securityPrivKey); |
3498 | 0 | u_char *tmpp = session->securityPrivKey; |
3499 | 0 | session->securityPrivKeyLen = 0; |
3500 | | /* it will be a hex string */ |
3501 | 0 | if (!snmp_hex_to_binary(&tmpp, &buflen, |
3502 | 0 | &session->securityPrivKeyLen, 0, cp)) { |
3503 | 0 | snmp_set_detail("error parsing encryption master key"); |
3504 | 0 | return SNMP_ERR_GENERR; |
3505 | 0 | } |
3506 | 0 | } else if ((in_session->securityPrivKeyLen <= 0) && |
3507 | 0 | ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
3508 | 0 | NETSNMP_DS_LIB_PRIVPASSPHRASE)) || |
3509 | 0 | (cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
3510 | 0 | NETSNMP_DS_LIB_PASSPHRASE)))) { |
3511 | 0 | session->securityPrivKeyLen = USM_PRIV_KU_LEN; |
3512 | 0 | if (generate_Ku(session->securityAuthProto, |
3513 | 0 | session->securityAuthProtoLen, |
3514 | 0 | (u_char *) cp, strlen(cp), |
3515 | 0 | session->securityPrivKey, |
3516 | 0 | &session->securityPrivKeyLen) != SNMPERR_SUCCESS) { |
3517 | 0 | snmp_set_detail |
3518 | 0 | ("Error generating a key (Ku) from the supplied privacy pass phrase."); |
3519 | 0 | return SNMP_ERR_GENERR; |
3520 | 0 | } |
3521 | 0 | } |
3522 | | |
3523 | 0 | return SNMPERR_SUCCESS; |
3524 | 0 | } |
3525 | | |
3526 | | static int usm_build_user(struct usmUser **result, |
3527 | | const netsnmp_session *session) |
3528 | 0 | { |
3529 | 0 | struct usmUser *user; |
3530 | |
|
3531 | 0 | DEBUGMSGTL(("usm", "Building user %s...\n", session->securityName)); |
3532 | | /* |
3533 | | * user doesn't exist so we create and add it |
3534 | | */ |
3535 | 0 | user = calloc(1, sizeof(struct usmUser)); |
3536 | 0 | if (user == NULL) |
3537 | 0 | goto err; |
3538 | | |
3539 | | /* |
3540 | | * copy in the securityName |
3541 | | */ |
3542 | 0 | if (session->securityName) { |
3543 | 0 | user->name = strdup(session->securityName); |
3544 | 0 | user->secName = strdup(session->securityName); |
3545 | 0 | if (user->name == NULL || user->secName == NULL) |
3546 | 0 | goto err; |
3547 | 0 | } |
3548 | | |
3549 | | /* |
3550 | | * copy in the engineID |
3551 | | */ |
3552 | 0 | user->engineID = netsnmp_memdup(session->securityEngineID, |
3553 | 0 | session->securityEngineIDLen); |
3554 | 0 | if (session->securityEngineID && !user->engineID) |
3555 | 0 | goto err; |
3556 | 0 | user->engineIDLen = session->securityEngineIDLen; |
3557 | 0 | *result = user; |
3558 | 0 | return SNMPERR_SUCCESS; |
3559 | | |
3560 | 0 | err: |
3561 | 0 | usm_free_user(user); |
3562 | 0 | return SNMPERR_GENERR; |
3563 | 0 | } |
3564 | | |
3565 | | /* |
3566 | | * usm_create_user_from_session(netsnmp_session *session): |
3567 | | * |
3568 | | * creates a user in the usm table from the information in a session. |
3569 | | * If the user already exists, it is updated with the current |
3570 | | * information from the session |
3571 | | * |
3572 | | * Parameters: |
3573 | | * session -- IN: pointer to the session to use when creating the user. |
3574 | | * |
3575 | | * Returns: |
3576 | | * SNMPERR_SUCCESS |
3577 | | * SNMPERR_GENERR |
3578 | | */ |
3579 | | int |
3580 | | usm_create_user_from_session(netsnmp_session * session) |
3581 | 0 | { |
3582 | 0 | struct usmUser *user; |
3583 | 0 | int user_just_created = 0; |
3584 | 0 | char *cp; |
3585 | | |
3586 | | /* |
3587 | | * - don't create-another/copy-into user for this session by default |
3588 | | * - bail now (no error) if we don't have an engineID |
3589 | | */ |
3590 | 0 | if (SNMP_FLAGS_USER_CREATED == (session->flags & SNMP_FLAGS_USER_CREATED) || |
3591 | 0 | session->securityModel != SNMP_SEC_MODEL_USM || |
3592 | 0 | session->version != SNMP_VERSION_3 || |
3593 | 0 | session->securityNameLen == 0 || |
3594 | 0 | session->securityEngineIDLen == 0) |
3595 | 0 | return SNMPERR_SUCCESS; |
3596 | | |
3597 | 0 | DEBUGMSGTL(("usm", "no flag defined... continuing\n")); |
3598 | 0 | session->flags |= SNMP_FLAGS_USER_CREATED; |
3599 | | |
3600 | | /* |
3601 | | * now that we have the engineID, create an entry in the USM list |
3602 | | * for this user using the information in the session |
3603 | | */ |
3604 | 0 | user = usm_get_user_from_list(session->securityEngineID, |
3605 | 0 | session->securityEngineIDLen, |
3606 | 0 | session->securityName, |
3607 | 0 | session->securityNameLen, |
3608 | 0 | usm_get_userList(), 0); |
3609 | 0 | if (NULL != user) { |
3610 | 0 | DEBUGMSGTL(("usm", "user exists x=%p\n", user)); |
3611 | 0 | } else { |
3612 | 0 | if (usm_build_user(&user, session) != SNMPERR_SUCCESS) |
3613 | 0 | return SNMPERR_GENERR; |
3614 | 0 | user_just_created = 1; |
3615 | 0 | } |
3616 | | |
3617 | | /* |
3618 | | * copy the auth protocol |
3619 | | */ |
3620 | 0 | if (user->authProtocol == NULL && session->securityAuthProto != NULL) { |
3621 | 0 | SNMP_FREE(user->authProtocol); |
3622 | 0 | user->authProtocol = |
3623 | 0 | snmp_duplicate_objid(session->securityAuthProto, |
3624 | 0 | session->securityAuthProtoLen); |
3625 | 0 | if (user->authProtocol == NULL) { |
3626 | 0 | usm_free_user(user); |
3627 | 0 | return SNMPERR_GENERR; |
3628 | 0 | } |
3629 | 0 | user->authProtocolLen = session->securityAuthProtoLen; |
3630 | 0 | } |
3631 | | |
3632 | | /* |
3633 | | * copy the priv protocol |
3634 | | */ |
3635 | 0 | if (user->privProtocol == NULL && session->securityPrivProto != NULL) { |
3636 | 0 | SNMP_FREE(user->privProtocol); |
3637 | 0 | user->privProtocol = |
3638 | 0 | snmp_duplicate_objid(session->securityPrivProto, |
3639 | 0 | session->securityPrivProtoLen); |
3640 | 0 | if (user->privProtocol == NULL) { |
3641 | 0 | usm_free_user(user); |
3642 | 0 | return SNMPERR_GENERR; |
3643 | 0 | } |
3644 | 0 | user->privProtocolLen = session->securityPrivProtoLen; |
3645 | 0 | } |
3646 | | |
3647 | | /* |
3648 | | * copy in the authentication Key. If not localized, localize it |
3649 | | */ |
3650 | 0 | if (user->authKey == NULL) { |
3651 | 0 | if (session->securityAuthLocalKey != NULL |
3652 | 0 | && session->securityAuthLocalKeyLen != 0) { |
3653 | | /* already localized key passed in. use it */ |
3654 | 0 | SNMP_FREE(user->authKey); |
3655 | 0 | user->authKey = netsnmp_memdup(session->securityAuthLocalKey, |
3656 | 0 | session->securityAuthLocalKeyLen); |
3657 | 0 | if (!user->authKey) { |
3658 | 0 | usm_free_user(user); |
3659 | 0 | return SNMPERR_GENERR; |
3660 | 0 | } |
3661 | 0 | user->authKeyLen = session->securityAuthLocalKeyLen; |
3662 | 0 | } else if (session->securityAuthKeyLen != 0) { |
3663 | 0 | SNMP_FREE(user->authKey); |
3664 | 0 | user->authKey = calloc(1, USM_LENGTH_KU_HASHBLOCK); |
3665 | 0 | user->authKeyLen = USM_LENGTH_KU_HASHBLOCK; |
3666 | 0 | if ((user->authKey == NULL) || |
3667 | 0 | generate_kul(user->authProtocol, user->authProtocolLen, |
3668 | 0 | user->engineID, user->engineIDLen, |
3669 | 0 | session->securityAuthKey, |
3670 | 0 | session->securityAuthKeyLen, user->authKey, |
3671 | 0 | &user->authKeyLen) != SNMPERR_SUCCESS) { |
3672 | 0 | usm_free_user(user); |
3673 | 0 | return SNMPERR_GENERR; |
3674 | 0 | } |
3675 | 0 | } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
3676 | 0 | NETSNMP_DS_LIB_AUTHLOCALIZEDKEY))) { |
3677 | 0 | size_t buflen = USM_AUTH_KU_LEN; |
3678 | 0 | SNMP_FREE(user->authKey); |
3679 | 0 | user->authKey = (u_char *)malloc(buflen); /* max length needed */ |
3680 | 0 | user->authKeyLen = 0; |
3681 | | /* it will be a hex string */ |
3682 | 0 | if ((NULL == user->authKey) || |
3683 | 0 | !snmp_hex_to_binary(&user->authKey, &buflen, &user->authKeyLen, |
3684 | 0 | 0, cp)) { |
3685 | 0 | usm_free_user(user); |
3686 | 0 | return SNMPERR_GENERR; |
3687 | 0 | } |
3688 | 0 | } |
3689 | 0 | } |
3690 | | |
3691 | | /* |
3692 | | * copy in the privacy Key. If not localized, localize it |
3693 | | */ |
3694 | 0 | if (user->privKey == NULL) { |
3695 | | /** save buffer size in case we need to extend key */ |
3696 | 0 | int keyBufSize = USM_PRIV_KU_LEN; |
3697 | |
|
3698 | 0 | DEBUGMSGTL(("usm", "copying privKey\n")); |
3699 | 0 | if (session->securityPrivLocalKey != NULL |
3700 | 0 | && session->securityPrivLocalKeyLen != 0) { |
3701 | | /* already localized key passed in. use it */ |
3702 | 0 | SNMP_FREE(user->privKey); |
3703 | 0 | user->privKey = netsnmp_memdup(session->securityPrivLocalKey, |
3704 | 0 | session->securityPrivLocalKeyLen); |
3705 | 0 | if (!user->privKey) { |
3706 | 0 | usm_free_user(user); |
3707 | 0 | return SNMPERR_GENERR; |
3708 | 0 | } |
3709 | 0 | keyBufSize = user->privKeyLen = session->securityPrivLocalKeyLen; |
3710 | 0 | } else if (session->securityPrivKeyLen != 0) { |
3711 | 0 | SNMP_FREE(user->privKey); |
3712 | 0 | user->privKey = calloc(1, keyBufSize); |
3713 | 0 | user->privKeyLen = keyBufSize; |
3714 | 0 | if ((user->privKey == NULL) || |
3715 | 0 | generate_kul(user->authProtocol, user->authProtocolLen, |
3716 | 0 | user->engineID, user->engineIDLen, |
3717 | 0 | session->securityPrivKey, |
3718 | 0 | session->securityPrivKeyLen, user->privKey, |
3719 | 0 | &user->privKeyLen) != SNMPERR_SUCCESS) { |
3720 | 0 | usm_free_user(user); |
3721 | 0 | return SNMPERR_GENERR; |
3722 | 0 | } |
3723 | 0 | } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
3724 | 0 | NETSNMP_DS_LIB_PRIVLOCALIZEDKEY))) { |
3725 | 0 | size_t buflen = keyBufSize; |
3726 | 0 | user->privKey = (u_char *)malloc(buflen); /* max length needed */ |
3727 | 0 | user->privKeyLen = 0; |
3728 | | /* it will be a hex string */ |
3729 | 0 | if ((NULL == user->privKey) || |
3730 | 0 | !snmp_hex_to_binary(&user->privKey, &buflen, &user->privKeyLen, |
3731 | 0 | 0, cp)) { |
3732 | 0 | usm_free_user(user); |
3733 | 0 | return SNMPERR_GENERR; |
3734 | 0 | } |
3735 | 0 | } |
3736 | 0 | if (usm_extend_user_kul(user, keyBufSize) != SNMPERR_SUCCESS) { |
3737 | 0 | usm_free_user(user); |
3738 | 0 | return SNMPERR_GENERR; |
3739 | 0 | } |
3740 | 0 | } |
3741 | | |
3742 | 0 | if (user_just_created) { |
3743 | | /* |
3744 | | * add the user into the database |
3745 | | */ |
3746 | 0 | user->userStatus = RS_ACTIVE; |
3747 | 0 | user->userStorageType = ST_READONLY; |
3748 | 0 | usm_add_user(user); |
3749 | 0 | } |
3750 | 0 | DEBUGMSGTL(("9:usm", "user created\n")); |
3751 | |
|
3752 | 0 | return SNMPERR_SUCCESS; |
3753 | | |
3754 | |
|
3755 | 0 | } |
3756 | | |
3757 | | /* A wrapper around the hook */ |
3758 | | static int |
3759 | | usm_create_user_from_session_hook(struct session_list *slp, |
3760 | | netsnmp_session *session) |
3761 | 0 | { |
3762 | 0 | DEBUGMSGTL(("usm", "potentially bootstrapping the USM table from session data\n")); |
3763 | 0 | return usm_create_user_from_session(session); |
3764 | 0 | } |
3765 | | |
3766 | | static int |
3767 | | usm_build_probe_pdu(netsnmp_pdu **pdu) |
3768 | 0 | { |
3769 | 0 | struct usmUser *user; |
3770 | | |
3771 | | /* |
3772 | | * create the pdu |
3773 | | */ |
3774 | 0 | if (!pdu) |
3775 | 0 | return -1; |
3776 | 0 | *pdu = snmp_pdu_create(SNMP_MSG_GET); |
3777 | 0 | if (!(*pdu)) |
3778 | 0 | return -1; |
3779 | 0 | (*pdu)->version = SNMP_VERSION_3; |
3780 | 0 | (*pdu)->securityName = strdup(""); |
3781 | 0 | (*pdu)->securityNameLen = strlen((*pdu)->securityName); |
3782 | 0 | (*pdu)->securityLevel = SNMP_SEC_LEVEL_NOAUTH; |
3783 | 0 | (*pdu)->securityModel = SNMP_SEC_MODEL_USM; |
3784 | | |
3785 | | /* |
3786 | | * create the empty user |
3787 | | */ |
3788 | 0 | user = usm_get_user2(NULL, 0, (*pdu)->securityName, |
3789 | 0 | (*pdu)->securityNameLen); |
3790 | 0 | if (user == NULL) { |
3791 | 0 | user = calloc(1, sizeof(struct usmUser)); |
3792 | 0 | if (user == NULL) { |
3793 | 0 | snmp_free_pdu(*pdu); |
3794 | 0 | *pdu = (netsnmp_pdu *) NULL; |
3795 | 0 | return -1; |
3796 | 0 | } |
3797 | 0 | user->name = strdup((*pdu)->securityName); |
3798 | 0 | user->secName = strdup((*pdu)->securityName); |
3799 | 0 | user->authProtocolLen = OID_LENGTH(usmNoAuthProtocol); |
3800 | 0 | user->authProtocol = |
3801 | 0 | snmp_duplicate_objid(usmNoAuthProtocol, user->authProtocolLen); |
3802 | 0 | user->privProtocolLen = OID_LENGTH(usmNoPrivProtocol); |
3803 | 0 | user->privProtocol = |
3804 | 0 | snmp_duplicate_objid(usmNoPrivProtocol, user->privProtocolLen); |
3805 | 0 | usm_add_user(user); |
3806 | 0 | } |
3807 | 0 | return 0; |
3808 | 0 | } |
3809 | | |
3810 | | static int usm_discover_engineid(struct session_list *slp, |
3811 | | netsnmp_session *session) |
3812 | 0 | { |
3813 | 0 | netsnmp_pdu *pdu = NULL, *response = NULL; |
3814 | 0 | int status, i; |
3815 | |
|
3816 | 0 | if (usm_build_probe_pdu(&pdu) != 0) { |
3817 | 0 | DEBUGMSGTL(("snmp_api", "unable to create probe PDU\n")); |
3818 | 0 | return SNMP_ERR_GENERR; |
3819 | 0 | } |
3820 | 0 | DEBUGMSGTL(("snmp_api", "probing for engineID...\n")); |
3821 | 0 | session->flags |= SNMP_FLAGS_DONT_PROBE; /* prevent recursion */ |
3822 | 0 | status = snmp_sess_synch_response(slp, pdu, &response); |
3823 | |
|
3824 | 0 | if ((response == NULL) && (status == STAT_SUCCESS)) { |
3825 | 0 | status = STAT_ERROR; |
3826 | 0 | } |
3827 | |
|
3828 | 0 | switch (status) { |
3829 | 0 | case STAT_SUCCESS: |
3830 | 0 | session->s_snmp_errno = SNMPERR_INVALID_MSG; /* XX?? */ |
3831 | 0 | DEBUGMSGTL(("snmp_sess_open", |
3832 | 0 | "error: expected Report as response to probe: %s (%ld)\n", |
3833 | 0 | snmp_errstring(response->errstat), |
3834 | 0 | response->errstat)); |
3835 | 0 | break; |
3836 | 0 | case STAT_ERROR: /* this is what we expected -> Report == STAT_ERROR */ |
3837 | 0 | session->s_snmp_errno = SNMPERR_UNKNOWN_ENG_ID; |
3838 | 0 | break; |
3839 | 0 | case STAT_TIMEOUT: |
3840 | 0 | session->s_snmp_errno = SNMPERR_TIMEOUT; |
3841 | 0 | break; |
3842 | 0 | default: |
3843 | 0 | DEBUGMSGTL(("snmp_sess_open", |
3844 | 0 | "unable to connect with remote engine: %s (%d)\n", |
3845 | 0 | snmp_api_errstring(session->s_snmp_errno), |
3846 | 0 | session->s_snmp_errno)); |
3847 | 0 | break; |
3848 | 0 | } |
3849 | | |
3850 | 0 | if (slp->session->securityEngineIDLen == 0) { |
3851 | 0 | DEBUGMSGTL(("snmp_api", |
3852 | 0 | "unable to determine remote engine ID\n")); |
3853 | | /* clear the flag so that probe occurs on next inform */ |
3854 | 0 | session->flags &= ~SNMP_FLAGS_DONT_PROBE; |
3855 | 0 | return SNMP_ERR_GENERR; |
3856 | 0 | } |
3857 | | |
3858 | 0 | session->s_snmp_errno = SNMPERR_SUCCESS; |
3859 | 0 | if (snmp_get_do_debugging()) { |
3860 | 0 | DEBUGMSGTL(("snmp_sess_open", |
3861 | 0 | " probe found engineID: ")); |
3862 | 0 | for (i = 0; i < slp->session->securityEngineIDLen; i++) |
3863 | 0 | DEBUGMSG(("snmp_sess_open", "%02x", |
3864 | 0 | slp->session->securityEngineID[i])); |
3865 | 0 | DEBUGMSG(("snmp_sess_open", "\n")); |
3866 | 0 | } |
3867 | | |
3868 | | /* |
3869 | | * if boot/time supplied set it for this engineID |
3870 | | */ |
3871 | 0 | if (session->engineBoots || session->engineTime) { |
3872 | 0 | set_enginetime(session->securityEngineID, |
3873 | 0 | session->securityEngineIDLen, |
3874 | 0 | session->engineBoots, session->engineTime, |
3875 | 0 | TRUE); |
3876 | 0 | } |
3877 | 0 | return SNMPERR_SUCCESS; |
3878 | 0 | } |
3879 | | |
3880 | | static int |
3881 | | usm_lookup_alg_type(const char *str, const usm_alg_type_t *types) |
3882 | 0 | { |
3883 | 0 | int i, l; |
3884 | 0 | l = strlen(str); |
3885 | 0 | for (i = 0; types[i].label; ++i) { |
3886 | 0 | if (0 == strncasecmp(types[i].label, str, l)) |
3887 | 0 | return types[i].value; |
3888 | 0 | } |
3889 | | |
3890 | 0 | return -1; |
3891 | 0 | } |
3892 | | |
3893 | | static const char * |
3894 | | usm_lookup_alg_str(int value, const usm_alg_type_t *types) |
3895 | 0 | { |
3896 | 0 | int i; |
3897 | 0 | for (i = 0; types[i].label; ++i) |
3898 | 0 | if (value == types[i].value) |
3899 | 0 | return types[i].label; |
3900 | | |
3901 | 0 | return NULL; |
3902 | 0 | } |
3903 | | |
3904 | | int |
3905 | | usm_lookup_auth_type(const char *str) |
3906 | 0 | { |
3907 | 0 | return usm_lookup_alg_type(str, usm_auth_type ); |
3908 | 0 | } |
3909 | | |
3910 | | int |
3911 | | usm_lookup_priv_type(const char *str) |
3912 | 0 | { |
3913 | 0 | return usm_lookup_alg_type(str, usm_priv_type ); |
3914 | 0 | } |
3915 | | |
3916 | | const char * |
3917 | | usm_lookup_auth_str(int value) |
3918 | 0 | { |
3919 | 0 | return usm_lookup_alg_str(value, usm_auth_type ); |
3920 | 0 | } |
3921 | | |
3922 | | const char * |
3923 | | usm_lookup_priv_str(int value) |
3924 | 0 | { |
3925 | 0 | return usm_lookup_alg_str(value, usm_priv_type ); |
3926 | 0 | } |
3927 | | |
3928 | | static void |
3929 | | clear_user_list(void) |
3930 | 0 | { |
3931 | 0 | struct usmUser *tmp = userList, *next = NULL; |
3932 | |
|
3933 | 0 | while (tmp != NULL) { |
3934 | 0 | next = tmp->next; |
3935 | 0 | usm_free_user(tmp); |
3936 | 0 | tmp = next; |
3937 | 0 | } |
3938 | 0 | userList = NULL; |
3939 | |
|
3940 | 0 | } |
3941 | | |
3942 | | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3943 | | /* |
3944 | | * take a given user and clone the security info into another |
3945 | | */ |
3946 | | struct usmUser * |
3947 | | usm_cloneFrom_user(struct usmUser *from, struct usmUser *to) |
3948 | 0 | { |
3949 | 0 | to->flags = from->flags; |
3950 | | |
3951 | | /* |
3952 | | * copy the authProtocol oid row pointer |
3953 | | */ |
3954 | 0 | SNMP_FREE(to->authProtocol); |
3955 | |
|
3956 | 0 | if ((to->authProtocol = |
3957 | 0 | snmp_duplicate_objid(from->authProtocol, |
3958 | 0 | from->authProtocolLen)) != NULL) |
3959 | 0 | to->authProtocolLen = from->authProtocolLen; |
3960 | 0 | else |
3961 | 0 | to->authProtocolLen = 0; |
3962 | | |
3963 | | |
3964 | | /* |
3965 | | * copy the authKey |
3966 | | */ |
3967 | 0 | SNMP_FREE(to->authKey); |
3968 | |
|
3969 | 0 | if (from->authKeyLen > 0 && |
3970 | 0 | (to->authKey = (u_char *) malloc(from->authKeyLen)) |
3971 | 0 | != NULL) { |
3972 | 0 | to->authKeyLen = from->authKeyLen; |
3973 | 0 | memcpy(to->authKey, from->authKey, to->authKeyLen); |
3974 | 0 | } else { |
3975 | 0 | to->authKey = NULL; |
3976 | 0 | to->authKeyLen = 0; |
3977 | 0 | } |
3978 | | |
3979 | | /* |
3980 | | * copy the authKeyKu |
3981 | | */ |
3982 | 0 | SNMP_FREE(to->authKeyKu); |
3983 | |
|
3984 | 0 | if (from->authKeyKuLen > 0 && |
3985 | 0 | (to->authKeyKu = (u_char *) malloc(from->authKeyKuLen)) != NULL) { |
3986 | 0 | to->authKeyKuLen = from->authKeyKuLen; |
3987 | 0 | memcpy(to->authKeyKu, from->authKeyKu, to->authKeyKuLen); |
3988 | 0 | } else { |
3989 | 0 | to->authKeyKu = NULL; |
3990 | 0 | to->authKeyKuLen = 0; |
3991 | 0 | } |
3992 | | |
3993 | | |
3994 | | /* |
3995 | | * copy the privProtocol oid row pointer |
3996 | | */ |
3997 | 0 | SNMP_FREE(to->privProtocol); |
3998 | |
|
3999 | 0 | if ((to->privProtocol = |
4000 | 0 | snmp_duplicate_objid(from->privProtocol, |
4001 | 0 | from->privProtocolLen)) != NULL) |
4002 | 0 | to->privProtocolLen = from->privProtocolLen; |
4003 | 0 | else |
4004 | 0 | to->privProtocolLen = 0; |
4005 | | |
4006 | | /* |
4007 | | * copy the privKey |
4008 | | */ |
4009 | 0 | SNMP_FREE(to->privKey); |
4010 | |
|
4011 | 0 | if (from->privKeyLen > 0 && |
4012 | 0 | (to->privKey = (u_char *) malloc(from->privKeyLen)) |
4013 | 0 | != NULL) { |
4014 | 0 | to->privKeyLen = from->privKeyLen; |
4015 | 0 | memcpy(to->privKey, from->privKey, to->privKeyLen); |
4016 | 0 | } else { |
4017 | 0 | to->privKey = NULL; |
4018 | 0 | to->privKeyLen = 0; |
4019 | 0 | } |
4020 | | |
4021 | | /* |
4022 | | * copy the privKeyKu |
4023 | | */ |
4024 | 0 | SNMP_FREE(to->privKeyKu); |
4025 | 0 | if (from->privKeyKuLen > 0 && |
4026 | 0 | (to->privKeyKu = (u_char *) malloc(from->privKeyKuLen)) != NULL) { |
4027 | 0 | to->privKeyKuLen = from->privKeyKuLen; |
4028 | 0 | memcpy(to->privKeyKu, from->privKeyKu, to->privKeyKuLen); |
4029 | 0 | } else { |
4030 | 0 | to->privKeyKu = NULL; |
4031 | 0 | to->privKeyKuLen = 0; |
4032 | 0 | } |
4033 | 0 | return to; |
4034 | 0 | } |
4035 | | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
4036 | | |
4037 | | /* |
4038 | | * usm_create_user(void): |
4039 | | * create a default empty user, instantiating only the auth/priv |
4040 | | * protocols to noAuth and noPriv OID pointers |
4041 | | */ |
4042 | | struct usmUser * |
4043 | | usm_create_user(void) |
4044 | 0 | { |
4045 | 0 | struct usmUser *newUser; |
4046 | | |
4047 | | /* |
4048 | | * create the new user |
4049 | | */ |
4050 | 0 | newUser = calloc(1, sizeof(struct usmUser)); |
4051 | 0 | if (newUser == NULL) |
4052 | 0 | return NULL; |
4053 | | |
4054 | | /* |
4055 | | * fill the auth/priv protocols |
4056 | | */ |
4057 | 0 | if ((newUser->authProtocol = |
4058 | 0 | snmp_duplicate_objid(usmNoAuthProtocol, |
4059 | 0 | OID_LENGTH(usmNoAuthProtocol))) == |
4060 | 0 | NULL) |
4061 | 0 | return usm_free_user(newUser); |
4062 | 0 | newUser->authProtocolLen = OID_LENGTH(usmNoAuthProtocol); |
4063 | |
|
4064 | 0 | if ((newUser->privProtocol = |
4065 | 0 | snmp_duplicate_objid(usmNoPrivProtocol, |
4066 | 0 | OID_LENGTH(usmNoPrivProtocol))) == |
4067 | 0 | NULL) |
4068 | 0 | return usm_free_user(newUser); |
4069 | 0 | newUser->privProtocolLen = OID_LENGTH(usmNoPrivProtocol); |
4070 | | |
4071 | | /* |
4072 | | * set the storage type to nonvolatile, and the status to ACTIVE |
4073 | | */ |
4074 | 0 | newUser->userStorageType = ST_NONVOLATILE; |
4075 | 0 | newUser->userStatus = RS_ACTIVE; |
4076 | 0 | return newUser; |
4077 | |
|
4078 | 0 | } /* end usm_clone_user() */ |
4079 | | |
4080 | | /* |
4081 | | * usm_create_initial_user(void): |
4082 | | * creates an initial user, filled with the defaults defined in the |
4083 | | * USM document. |
4084 | | */ |
4085 | | static struct usmUser * |
4086 | | usm_create_initial_user(const char *name, |
4087 | | const oid * authProtocol, size_t authProtocolLen, |
4088 | | const oid * privProtocol, size_t privProtocolLen) |
4089 | 0 | { |
4090 | 0 | struct usmUser *newUser = usm_create_user(); |
4091 | 0 | if (newUser == NULL) |
4092 | 0 | return NULL; |
4093 | | |
4094 | 0 | if ((newUser->name = strdup(name)) == NULL) |
4095 | 0 | return usm_free_user(newUser); |
4096 | | |
4097 | 0 | if ((newUser->secName = strdup(name)) == NULL) |
4098 | 0 | return usm_free_user(newUser); |
4099 | | |
4100 | 0 | if ((newUser->engineID = |
4101 | 0 | snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL) |
4102 | 0 | return usm_free_user(newUser); |
4103 | | |
4104 | 0 | if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid) * 2)) == NULL) |
4105 | 0 | return usm_free_user(newUser); |
4106 | 0 | newUser->cloneFrom[0] = 0; |
4107 | 0 | newUser->cloneFrom[1] = 0; |
4108 | 0 | newUser->cloneFromLen = 2; |
4109 | |
|
4110 | 0 | SNMP_FREE(newUser->privProtocol); |
4111 | 0 | if ((newUser->privProtocol = snmp_duplicate_objid(privProtocol, |
4112 | 0 | privProtocolLen)) == |
4113 | 0 | NULL) { |
4114 | 0 | return usm_free_user(newUser); |
4115 | 0 | } |
4116 | 0 | newUser->privProtocolLen = privProtocolLen; |
4117 | |
|
4118 | 0 | SNMP_FREE(newUser->authProtocol); |
4119 | 0 | if ((newUser->authProtocol = snmp_duplicate_objid(authProtocol, |
4120 | 0 | authProtocolLen)) == |
4121 | 0 | NULL) { |
4122 | 0 | return usm_free_user(newUser); |
4123 | 0 | } |
4124 | 0 | newUser->authProtocolLen = authProtocolLen; |
4125 | |
|
4126 | 0 | newUser->userStatus = RS_ACTIVE; |
4127 | 0 | newUser->userStorageType = ST_READONLY; |
4128 | |
|
4129 | 0 | return newUser; |
4130 | 0 | } |
4131 | | |
4132 | | /* |
4133 | | * usm_save_user(): saves a user to the persistent cache |
4134 | | */ |
4135 | | static void |
4136 | | usm_save_user(struct usmUser *user, const char *token, const char *type) |
4137 | 0 | { |
4138 | 0 | char line[4096]; |
4139 | 0 | char *cptr; |
4140 | |
|
4141 | 0 | memset(line, 0, sizeof(line)); |
4142 | |
|
4143 | 0 | sprintf(line, "%s %d %d ", token, user->userStatus, |
4144 | 0 | user->userStorageType); |
4145 | 0 | cptr = &line[strlen(line)]; /* the NULL */ |
4146 | 0 | cptr = |
4147 | 0 | read_config_save_octet_string(cptr, user->engineID, |
4148 | 0 | user->engineIDLen); |
4149 | 0 | *cptr++ = ' '; |
4150 | 0 | cptr = read_config_save_octet_string(cptr, (u_char *) user->name, |
4151 | 0 | (user->name == NULL) ? 0 : |
4152 | 0 | strlen(user->name)); |
4153 | 0 | *cptr++ = ' '; |
4154 | 0 | cptr = read_config_save_octet_string(cptr, (u_char *) user->secName, |
4155 | 0 | (user->secName == NULL) ? 0 : |
4156 | 0 | strlen(user->secName)); |
4157 | 0 | *cptr++ = ' '; |
4158 | 0 | cptr = |
4159 | 0 | read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen); |
4160 | 0 | *cptr++ = ' '; |
4161 | 0 | cptr = read_config_save_objid(cptr, user->authProtocol, |
4162 | 0 | user->authProtocolLen); |
4163 | 0 | *cptr++ = ' '; |
4164 | 0 | cptr = |
4165 | 0 | read_config_save_octet_string(cptr, user->authKey, |
4166 | 0 | user->authKeyLen); |
4167 | 0 | *cptr++ = ' '; |
4168 | 0 | cptr = read_config_save_objid(cptr, user->privProtocol, |
4169 | 0 | user->privProtocolLen); |
4170 | 0 | *cptr++ = ' '; |
4171 | 0 | cptr = |
4172 | 0 | read_config_save_octet_string(cptr, user->privKey, |
4173 | 0 | user->privKeyLen); |
4174 | 0 | *cptr++ = ' '; |
4175 | 0 | cptr = read_config_save_octet_string(cptr, user->userPublicString, |
4176 | 0 | user->userPublicStringLen); |
4177 | |
|
4178 | 0 | read_config_store(type, line); |
4179 | 0 | } |
4180 | | |
4181 | | static void |
4182 | | usm_save_users_from_list(struct usmUser *puserList, const char *token, |
4183 | | const char *type) |
4184 | 0 | { |
4185 | 0 | struct usmUser *uptr; |
4186 | 0 | for (uptr = puserList; uptr != NULL; uptr = uptr->next) { |
4187 | 0 | if (uptr->userStorageType == ST_NONVOLATILE) |
4188 | 0 | usm_save_user(uptr, token, type); |
4189 | 0 | } |
4190 | 0 | } |
4191 | | |
4192 | | /* |
4193 | | * usm_save_users(): saves a list of users to the persistent cache |
4194 | | */ |
4195 | | static void |
4196 | | usm_save_users(const char *token, const char *type) |
4197 | 0 | { |
4198 | 0 | usm_save_users_from_list(userList, token, type); |
4199 | 0 | } |
4200 | | |
4201 | | /* |
4202 | | * this is a callback that can store all known users based on a |
4203 | | * previously registered application ID |
4204 | | */ |
4205 | | static int |
4206 | | usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg) |
4207 | 0 | { |
4208 | | /* |
4209 | | * figure out our application name |
4210 | | */ |
4211 | 0 | char *appname = (char *) clientarg; |
4212 | 0 | if (appname == NULL) { |
4213 | 0 | appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
4214 | 0 | NETSNMP_DS_LIB_APPTYPE); |
4215 | 0 | } |
4216 | | |
4217 | | /* |
4218 | | * save the user base |
4219 | | */ |
4220 | 0 | usm_save_users("usmUser", appname); |
4221 | | |
4222 | | /* |
4223 | | * never fails |
4224 | | */ |
4225 | 0 | return SNMPERR_SUCCESS; |
4226 | 0 | } |
4227 | | |
4228 | | /* |
4229 | | * usm_parse_user(): reads in a line containing a saved user profile |
4230 | | * and returns a pointer to a newly created struct usmUser. |
4231 | | */ |
4232 | | static struct usmUser * |
4233 | | usm_read_user(const char *line) |
4234 | 0 | { |
4235 | 0 | struct usmUser *user; |
4236 | 0 | size_t len, proper_length, privtype; |
4237 | |
|
4238 | 0 | user = usm_create_user(); |
4239 | 0 | if (user == NULL) |
4240 | 0 | return NULL; |
4241 | | |
4242 | 0 | user->userStatus = atoi(line); |
4243 | 0 | line = skip_token_const(line); |
4244 | 0 | user->userStorageType = atoi(line); |
4245 | 0 | line = skip_token_const(line); |
4246 | 0 | line = read_config_read_octet_string_const(line, &user->engineID, |
4247 | 0 | &user->engineIDLen); |
4248 | | |
4249 | | /* |
4250 | | * set the lcd entry for this engineID to the minimum boots/time |
4251 | | * values so that its a known engineid and won't return a report pdu. |
4252 | | * This is mostly important when receiving v3 traps so that the usm |
4253 | | * will at least continue processing them. |
4254 | | */ |
4255 | 0 | set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0); |
4256 | |
|
4257 | 0 | line = read_config_read_octet_string(line, (u_char **) & user->name, |
4258 | 0 | &len); |
4259 | 0 | line = read_config_read_octet_string(line, (u_char **) & user->secName, |
4260 | 0 | &len); |
4261 | 0 | SNMP_FREE(user->cloneFrom); |
4262 | 0 | user->cloneFromLen = 0; |
4263 | |
|
4264 | 0 | line = read_config_read_objid_const(line, &user->cloneFrom, |
4265 | 0 | &user->cloneFromLen); |
4266 | |
|
4267 | 0 | SNMP_FREE(user->authProtocol); |
4268 | 0 | user->authProtocolLen = 0; |
4269 | |
|
4270 | 0 | line = read_config_read_objid_const(line, &user->authProtocol, |
4271 | 0 | &user->authProtocolLen); |
4272 | 0 | line = read_config_read_octet_string_const(line, &user->authKey, |
4273 | 0 | &user->authKeyLen); |
4274 | 0 | SNMP_FREE(user->privProtocol); |
4275 | 0 | user->privProtocolLen = 0; |
4276 | |
|
4277 | 0 | line = read_config_read_objid_const(line, &user->privProtocol, |
4278 | 0 | &user->privProtocolLen); |
4279 | 0 | line = read_config_read_octet_string(line, &user->privKey, |
4280 | 0 | &user->privKeyLen); |
4281 | |
|
4282 | 0 | privtype = sc_get_privtype(user->privProtocol, user->privProtocolLen); |
4283 | 0 | proper_length = sc_get_proper_priv_length_bytype(privtype); |
4284 | 0 | if (USM_CREATE_USER_PRIV_DES == privtype) |
4285 | 0 | proper_length *= 2; /* ?? we store salt with key */ |
4286 | | /* For backwards compatibility */ |
4287 | 0 | if (user->privKeyLen > proper_length) { |
4288 | 0 | user->privKeyLen = proper_length; |
4289 | 0 | } |
4290 | |
|
4291 | 0 | line = read_config_read_octet_string(line, &user->userPublicString, |
4292 | 0 | &user->userPublicStringLen); |
4293 | 0 | return user; |
4294 | 0 | } |
4295 | | |
4296 | | /* |
4297 | | * snmpd.conf parsing routines |
4298 | | */ |
4299 | | void |
4300 | | usm_parse_config_usmUser(const char *token, char *line) |
4301 | 0 | { |
4302 | 0 | struct usmUser *uptr; |
4303 | |
|
4304 | 0 | uptr = usm_read_user(line); |
4305 | 0 | if ( uptr) |
4306 | 0 | usm_add_user(uptr); |
4307 | 0 | } |
4308 | | |
4309 | | /*******************************************************************-o-****** |
4310 | | * usm_set_password |
4311 | | * |
4312 | | * Parameters: |
4313 | | * *token |
4314 | | * *line |
4315 | | * |
4316 | | * |
4317 | | * format: userSetAuthPass secname engineIDLen engineID pass |
4318 | | * or: userSetPrivPass secname engineIDLen engineID pass |
4319 | | * or: userSetAuthKey secname engineIDLen engineID KuLen Ku |
4320 | | * or: userSetPrivKey secname engineIDLen engineID KuLen Ku |
4321 | | * or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul |
4322 | | * or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul |
4323 | | * |
4324 | | * type is: 1=passphrase; 2=Ku; 3=Kul. |
4325 | | * |
4326 | | * |
4327 | | * ASSUMES Passwords are null-terminated printable strings. |
4328 | | */ |
4329 | | static void |
4330 | | usm_set_password(const char *token, char *line) |
4331 | 0 | { |
4332 | 0 | char *cp; |
4333 | 0 | char nameBuf[SNMP_MAXBUF]; |
4334 | 0 | u_char *engineID = NULL; |
4335 | 0 | size_t engineIDLen = 0; |
4336 | 0 | struct usmUser *user; |
4337 | |
|
4338 | 0 | cp = copy_nword(line, nameBuf, sizeof(nameBuf)); |
4339 | 0 | if (cp == NULL) { |
4340 | 0 | config_perror("invalid name specifier"); |
4341 | 0 | return; |
4342 | 0 | } |
4343 | | |
4344 | 0 | DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING)); |
4345 | 0 | if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) { |
4346 | | /* |
4347 | | * match against all engineIDs we know about |
4348 | | */ |
4349 | 0 | cp = skip_token(cp); |
4350 | 0 | for (user = userList; user != NULL; user = user->next) { |
4351 | 0 | if (user->secName && strcmp(user->secName, nameBuf) == 0) { |
4352 | 0 | usm_set_user_password(user, token, cp); |
4353 | 0 | } |
4354 | 0 | } |
4355 | 0 | } else { |
4356 | 0 | cp = read_config_read_octet_string(cp, &engineID, &engineIDLen); |
4357 | 0 | if (cp == NULL) { |
4358 | 0 | config_perror("invalid engineID specifier"); |
4359 | 0 | SNMP_FREE(engineID); |
4360 | 0 | return; |
4361 | 0 | } |
4362 | | |
4363 | 0 | user = usm_get_user(engineID, engineIDLen, nameBuf); |
4364 | 0 | if (user == NULL) { |
4365 | 0 | config_perror("not a valid user/engineID pair"); |
4366 | 0 | SNMP_FREE(engineID); |
4367 | 0 | return; |
4368 | 0 | } |
4369 | 0 | usm_set_user_password(user, token, cp); |
4370 | 0 | SNMP_FREE(engineID); |
4371 | 0 | } |
4372 | 0 | } |
4373 | | |
4374 | | /* |
4375 | | * uses the rest of LINE to configure USER's password of type TOKEN |
4376 | | */ |
4377 | | void |
4378 | | usm_set_user_password(struct usmUser *user, const char *token, char *line) |
4379 | 0 | { |
4380 | 0 | char *cp = line; |
4381 | 0 | u_char *engineID = user->engineID; |
4382 | 0 | size_t engineIDLen = user->engineIDLen; |
4383 | |
|
4384 | 0 | u_char **key; |
4385 | 0 | size_t *keyLen; |
4386 | 0 | u_char userKey[SNMP_MAXBUF_SMALL]; |
4387 | 0 | size_t userKeyLen = SNMP_MAXBUF_SMALL; |
4388 | 0 | u_char *userKeyP = userKey; |
4389 | 0 | int type, ret; |
4390 | | |
4391 | | /* |
4392 | | * Retrieve the "old" key and set the key type. |
4393 | | */ |
4394 | 0 | if (!token) { |
4395 | 0 | return; |
4396 | 0 | } else if (strcmp(token, "userSetAuthPass") == 0) { |
4397 | 0 | key = &user->authKey; |
4398 | 0 | keyLen = &user->authKeyLen; |
4399 | 0 | type = 0; |
4400 | 0 | } else if (strcmp(token, "userSetPrivPass") == 0) { |
4401 | 0 | key = &user->privKey; |
4402 | 0 | keyLen = &user->privKeyLen; |
4403 | 0 | type = 0; |
4404 | 0 | } else if (strcmp(token, "userSetAuthKey") == 0) { |
4405 | 0 | key = &user->authKey; |
4406 | 0 | keyLen = &user->authKeyLen; |
4407 | 0 | type = 1; |
4408 | 0 | } else if (strcmp(token, "userSetPrivKey") == 0) { |
4409 | 0 | key = &user->privKey; |
4410 | 0 | keyLen = &user->privKeyLen; |
4411 | 0 | type = 1; |
4412 | 0 | } else if (strcmp(token, "userSetAuthLocalKey") == 0) { |
4413 | 0 | key = &user->authKey; |
4414 | 0 | keyLen = &user->authKeyLen; |
4415 | 0 | type = 2; |
4416 | 0 | } else if (strcmp(token, "userSetPrivLocalKey") == 0) { |
4417 | 0 | key = &user->privKey; |
4418 | 0 | keyLen = &user->privKeyLen; |
4419 | 0 | type = 2; |
4420 | 0 | } else { |
4421 | | /* |
4422 | | * no old key, or token was not recognized |
4423 | | */ |
4424 | 0 | return; |
4425 | 0 | } |
4426 | | |
4427 | 0 | if (*key) { |
4428 | | /* |
4429 | | * (destroy and) free the old key |
4430 | | */ |
4431 | 0 | memset(*key, 0, *keyLen); |
4432 | 0 | SNMP_FREE(*key); |
4433 | 0 | } |
4434 | |
|
4435 | 0 | if (type == 0) { |
4436 | | /* |
4437 | | * convert the password into a key |
4438 | | */ |
4439 | 0 | if (cp == NULL) { |
4440 | 0 | config_perror("missing user password"); |
4441 | 0 | return; |
4442 | 0 | } |
4443 | 0 | ret = generate_Ku(user->authProtocol, user->authProtocolLen, |
4444 | 0 | (u_char *) cp, strlen(cp), userKey, &userKeyLen); |
4445 | |
|
4446 | 0 | if (ret != SNMPERR_SUCCESS) { |
4447 | 0 | config_perror("setting key failed (in sc_genKu())"); |
4448 | 0 | return; |
4449 | 0 | } |
4450 | | /* save master key */ |
4451 | 0 | if (user->flags & USMUSER_FLAG_KEEP_MASTER_KEY) { |
4452 | 0 | if (userKey == user->privKey) { |
4453 | 0 | user->privKeyKu = netsnmp_memdup(userKey, userKeyLen); |
4454 | 0 | user->privKeyKuLen = userKeyLen; |
4455 | 0 | } else if (userKey == user->authKey) { |
4456 | 0 | user->authKeyKu = netsnmp_memdup(userKey, userKeyLen); |
4457 | 0 | user->authKeyKuLen = userKeyLen; |
4458 | 0 | } |
4459 | 0 | } |
4460 | 0 | } else if (type == 1) { |
4461 | 0 | cp = read_config_read_octet_string(cp, &userKeyP, &userKeyLen); |
4462 | |
|
4463 | 0 | if (cp == NULL) { |
4464 | 0 | config_perror("invalid user key"); |
4465 | 0 | return; |
4466 | 0 | } |
4467 | 0 | } |
4468 | | |
4469 | 0 | if (type < 2) { |
4470 | 0 | *key = (u_char *) malloc(SNMP_MAXBUF_SMALL); |
4471 | 0 | *keyLen = SNMP_MAXBUF_SMALL; |
4472 | 0 | ret = generate_kul(user->authProtocol, user->authProtocolLen, |
4473 | 0 | engineID, engineIDLen, |
4474 | 0 | userKey, userKeyLen, *key, keyLen); |
4475 | 0 | if (ret != SNMPERR_SUCCESS) { |
4476 | 0 | config_perror("setting key failed (in generate_kul())"); |
4477 | 0 | return; |
4478 | 0 | } |
4479 | | |
4480 | | /* |
4481 | | * (destroy and) free the old key |
4482 | | */ |
4483 | 0 | memset(userKey, 0, sizeof(userKey)); |
4484 | |
|
4485 | 0 | } else { |
4486 | | /* |
4487 | | * the key is given, copy it in |
4488 | | */ |
4489 | 0 | cp = read_config_read_octet_string(cp, key, keyLen); |
4490 | |
|
4491 | 0 | if (cp == NULL) { |
4492 | 0 | config_perror("invalid localized user key"); |
4493 | 0 | return; |
4494 | 0 | } |
4495 | 0 | } |
4496 | | |
4497 | 0 | if (key == &user->privKey) { |
4498 | 0 | ret = usm_extend_user_kul(user, *keyLen); |
4499 | 0 | if (SNMPERR_SUCCESS != ret) { |
4500 | 0 | config_perror("error extending localized user key"); |
4501 | 0 | return; |
4502 | 0 | } |
4503 | 0 | } |
4504 | 0 | } /* end usm_set_password() */ |
4505 | | |
4506 | | /* |
4507 | | * create a usm user from a string. |
4508 | | * |
4509 | | * The format for the string is described in the createUser |
4510 | | * secion of the snmpd.conf man page. |
4511 | | * |
4512 | | * On success, a pointer to the created usmUser struct is returned. |
4513 | | * On error, a NULL pointer is returned. In this case, if a pointer to a |
4514 | | * char pointer is provided in errorMsg, an error string is returned. |
4515 | | * This error string points to a static message, and should not be |
4516 | | * freed. |
4517 | | */ |
4518 | | static struct usmUser * |
4519 | | usm_create_usmUser_from_string(char *line, const char **errorMsg) |
4520 | 0 | { |
4521 | 0 | char *cp; |
4522 | 0 | const char *dummy; |
4523 | 0 | char buf[SNMP_MAXBUF_MEDIUM]; |
4524 | 0 | struct usmUser *newuser; |
4525 | 0 | u_char userKey[SNMP_MAXBUF_SMALL], *tmpp; |
4526 | 0 | size_t userKeyLen = SNMP_MAXBUF_SMALL; |
4527 | 0 | size_t privKeySize; |
4528 | 0 | size_t ret; |
4529 | 0 | int ret2, properLen, properPrivKeyLen; |
4530 | 0 | const oid *def_auth_prot, *def_priv_prot; |
4531 | 0 | size_t def_auth_prot_len, def_priv_prot_len; |
4532 | 0 | const netsnmp_priv_alg_info *pai; |
4533 | |
|
4534 | 0 | def_auth_prot = get_default_authtype(&def_auth_prot_len); |
4535 | 0 | def_priv_prot = get_default_privtype(&def_priv_prot_len); |
4536 | |
|
4537 | 0 | if (NULL == line) |
4538 | 0 | return NULL; |
4539 | | |
4540 | | #ifdef NETSNMP_ENABLE_TESTING_CODE |
4541 | | DEBUGMSGTL(("usmUser", "new user %s\n", line)); /* logs passphrases */ |
4542 | | #endif |
4543 | | |
4544 | 0 | if (NULL == errorMsg) |
4545 | 0 | errorMsg = &dummy; |
4546 | 0 | *errorMsg = NULL; /* no errors yet */ |
4547 | |
|
4548 | 0 | newuser = usm_create_user(); |
4549 | 0 | if (newuser == NULL) { |
4550 | 0 | *errorMsg = "malloc failure creating new user"; |
4551 | 0 | goto fail; |
4552 | 0 | } |
4553 | | |
4554 | | /* |
4555 | | * READ: Security Name |
4556 | | */ |
4557 | 0 | cp = copy_nword(line, buf, sizeof(buf)); |
4558 | | |
4559 | | /* |
4560 | | * check for (undocumented) 'keep master key' flag. so far, this is |
4561 | | * just used for users for informs (who need non-localized keys). |
4562 | | */ |
4563 | 0 | if (strcmp(buf, "-M") == 0) { |
4564 | 0 | newuser->flags |= USMUSER_FLAG_KEEP_MASTER_KEY; |
4565 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4566 | 0 | } |
4567 | | |
4568 | | /* |
4569 | | * might be a -e ENGINEID argument |
4570 | | */ |
4571 | 0 | if (strcmp(buf, "-e") == 0) { |
4572 | 0 | size_t ebuf_len = 32, eout_len = 0; |
4573 | 0 | u_char *ebuf = (u_char *) malloc(ebuf_len); |
4574 | |
|
4575 | 0 | if (ebuf == NULL) { |
4576 | 0 | *errorMsg = "malloc failure processing -e flag"; |
4577 | 0 | goto fail; |
4578 | 0 | } |
4579 | | |
4580 | | /* |
4581 | | * Get the specified engineid from the line. |
4582 | | */ |
4583 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4584 | 0 | if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, buf)) { |
4585 | 0 | *errorMsg = "invalid EngineID argument to -e"; |
4586 | 0 | SNMP_FREE(ebuf); |
4587 | 0 | goto fail; |
4588 | 0 | } |
4589 | | |
4590 | 0 | newuser->engineID = ebuf; |
4591 | 0 | newuser->engineIDLen = eout_len; |
4592 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4593 | 0 | } else { |
4594 | 0 | newuser->engineID = snmpv3_generate_engineID(&ret); |
4595 | 0 | if (ret == 0) { |
4596 | 0 | goto fail; |
4597 | 0 | } |
4598 | 0 | newuser->engineIDLen = ret; |
4599 | 0 | } |
4600 | | |
4601 | 0 | newuser->secName = strdup(buf); |
4602 | 0 | newuser->name = strdup(buf); |
4603 | |
|
4604 | 0 | if (!cp) { |
4605 | | #ifdef NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV |
4606 | | /** no passwords ok iff defaults are noauth/nopriv */ |
4607 | | if (snmp_oid_compare(usmNoAuthProtocol, OID_LENGTH(usmNoAuthProtocol), |
4608 | | def_auth_prot, def_auth_prot_len) != 0) { |
4609 | | *errorMsg = "no authentication pass phrase"; |
4610 | | goto fail; |
4611 | | } |
4612 | | if (snmp_oid_compare(usmNoPrivProtocol, OID_LENGTH(usmNoPrivProtocol), |
4613 | | def_priv_prot, def_priv_prot_len) != 0) { |
4614 | | *errorMsg = "no privacy pass phrase"; |
4615 | | goto fail; |
4616 | | } |
4617 | | #endif /* NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV */ |
4618 | 0 | goto add; /* no authentication or privacy type */ |
4619 | 0 | } |
4620 | | |
4621 | | /* |
4622 | | * READ: Authentication Type |
4623 | | */ |
4624 | 0 | newuser->authProtocol[0] = 0; |
4625 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4626 | 0 | if ((strncmp(cp, "default", 7) == 0) && (NULL != def_auth_prot)) { |
4627 | 0 | SNMP_FREE(newuser->authProtocol); |
4628 | 0 | newuser->authProtocol = snmp_duplicate_objid(def_auth_prot, |
4629 | 0 | def_auth_prot_len); |
4630 | 0 | if (newuser->authProtocol == NULL) { |
4631 | 0 | *errorMsg = "malloc failed"; |
4632 | 0 | goto fail; |
4633 | 0 | } |
4634 | 0 | newuser->authProtocolLen = def_auth_prot_len; |
4635 | 0 | } else { |
4636 | 0 | const oid *auth_prot; |
4637 | 0 | int auth_type = usm_lookup_auth_type(buf); |
4638 | 0 | if (auth_type < 0) { |
4639 | 0 | *errorMsg = "unknown authProtocol"; |
4640 | 0 | goto fail; |
4641 | 0 | } |
4642 | 0 | auth_prot = sc_get_auth_oid(auth_type, &newuser->authProtocolLen); |
4643 | 0 | if (auth_prot) { |
4644 | 0 | SNMP_FREE(newuser->authProtocol); |
4645 | 0 | newuser->authProtocol = |
4646 | 0 | snmp_duplicate_objid(auth_prot, newuser->authProtocolLen); |
4647 | 0 | } |
4648 | 0 | if (newuser->authProtocol == NULL) { |
4649 | 0 | *errorMsg = "malloc failed"; |
4650 | 0 | goto fail; |
4651 | 0 | } |
4652 | 0 | } |
4653 | 0 | if (0 == newuser->authProtocol[0]) { |
4654 | 0 | *errorMsg = "Unknown authentication protocol"; |
4655 | 0 | goto fail; |
4656 | 0 | } |
4657 | | #ifdef NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV |
4658 | | if (snmp_oid_compare(newuser->authProtocol, newuser->authProtocolLen, |
4659 | | def_auth_prot, def_auth_prot_len) != 0) { |
4660 | | *errorMsg = "auth protocol does not match system policy"; |
4661 | | goto fail; |
4662 | | } |
4663 | | #endif /* NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV */ |
4664 | | |
4665 | | /* |
4666 | | * READ: Authentication Pass Phrase or key |
4667 | | */ |
4668 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4669 | 0 | if (strcmp(buf,"-m") == 0) { |
4670 | | /* a master key is specified */ |
4671 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4672 | 0 | ret = sizeof(userKey); |
4673 | 0 | tmpp = userKey; |
4674 | 0 | userKeyLen = 0; |
4675 | 0 | if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) { |
4676 | 0 | *errorMsg = "invalid key value argument to -m"; |
4677 | 0 | goto fail; |
4678 | 0 | } |
4679 | | /* save master key */ |
4680 | 0 | if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) { |
4681 | 0 | newuser->authKeyKu = netsnmp_memdup(userKey, userKeyLen); |
4682 | 0 | newuser->authKeyKuLen = userKeyLen; |
4683 | 0 | } |
4684 | 0 | } else if (strcmp(buf,"-l") != 0) { |
4685 | | /* a password is specified */ |
4686 | 0 | userKeyLen = sizeof(userKey); |
4687 | 0 | ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen, |
4688 | 0 | (u_char *) buf, strlen(buf), userKey, &userKeyLen); |
4689 | 0 | if (ret2 != SNMPERR_SUCCESS) { |
4690 | 0 | *errorMsg = "could not generate the authentication key from the supplied pass phrase."; |
4691 | 0 | goto fail; |
4692 | 0 | } |
4693 | | /* save master key */ |
4694 | 0 | if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) { |
4695 | 0 | newuser->authKeyKu = netsnmp_memdup(userKey, userKeyLen); |
4696 | 0 | newuser->authKeyKuLen = userKeyLen; |
4697 | 0 | } |
4698 | 0 | } |
4699 | | |
4700 | | /* |
4701 | | * And turn it into a localized key |
4702 | | */ |
4703 | 0 | properLen = sc_get_proper_auth_length_bytype( |
4704 | 0 | sc_get_authtype(newuser->authProtocol, newuser->authProtocolLen)); |
4705 | 0 | if (properLen <= 0) { |
4706 | 0 | *errorMsg = "Could not get proper authentication protocol key length"; |
4707 | 0 | goto fail; |
4708 | 0 | } |
4709 | 0 | newuser->authKey = (u_char *) malloc(properLen); |
4710 | 0 | newuser->authKeyLen = properLen; |
4711 | |
|
4712 | 0 | if (strcmp(buf,"-l") == 0) { |
4713 | | /* a local key is directly specified */ |
4714 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4715 | 0 | ret = newuser->authKeyLen; |
4716 | 0 | newuser->authKeyLen = 0; |
4717 | 0 | if (!snmp_hex_to_binary(&newuser->authKey, &ret, |
4718 | 0 | &newuser->authKeyLen, 0, buf)) { |
4719 | 0 | *errorMsg = "invalid key value argument to -l"; |
4720 | 0 | goto fail; |
4721 | 0 | } |
4722 | 0 | if (properLen != newuser->authKeyLen) { |
4723 | 0 | *errorMsg = "improper key length to -l"; |
4724 | 0 | goto fail; |
4725 | 0 | } |
4726 | 0 | } else { |
4727 | 0 | ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen, |
4728 | 0 | newuser->engineID, newuser->engineIDLen, |
4729 | 0 | userKey, userKeyLen, |
4730 | 0 | newuser->authKey, &newuser->authKeyLen); |
4731 | 0 | if (ret2 != SNMPERR_SUCCESS) { |
4732 | 0 | *errorMsg = "could not generate localized authentication key (Kul) from the master key (Ku)."; |
4733 | 0 | goto fail; |
4734 | 0 | } |
4735 | 0 | } |
4736 | | |
4737 | 0 | if (!cp) { |
4738 | 0 | #ifndef NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV |
4739 | 0 | goto add; /* no privacy type (which is legal) */ |
4740 | | #else |
4741 | | if (snmp_oid_compare(usmNoPrivProtocol, OID_LENGTH(usmNoPrivProtocol), |
4742 | | def_priv_prot, def_priv_prot_len) == 0) |
4743 | | goto add; |
4744 | | else { |
4745 | | *errorMsg = "priv protocol does not match system policy"; |
4746 | | goto fail; |
4747 | | } |
4748 | | #endif /* NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV */ |
4749 | 0 | } |
4750 | | |
4751 | | /* |
4752 | | * READ: Privacy Type |
4753 | | */ |
4754 | 0 | newuser->privProtocol[0] = 0; |
4755 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4756 | 0 | if ((strncmp(buf, "default", 7) == 0) && (NULL != def_priv_prot)) { |
4757 | 0 | SNMP_FREE(newuser->privProtocol); |
4758 | 0 | newuser->privProtocol = |
4759 | 0 | snmp_duplicate_objid(def_priv_prot, def_priv_prot_len); |
4760 | 0 | if (newuser->privProtocol == NULL) { |
4761 | 0 | *errorMsg = "malloc failed"; |
4762 | 0 | goto fail; |
4763 | 0 | } |
4764 | 0 | newuser->privProtocolLen = def_priv_prot_len; |
4765 | 0 | pai = sc_get_priv_alg_byoid(newuser->privProtocol, |
4766 | 0 | newuser->privProtocolLen); |
4767 | 0 | } else { |
4768 | 0 | int priv_type = usm_lookup_priv_type(buf); |
4769 | 0 | if (priv_type < 0) { |
4770 | 0 | *errorMsg = "unknown privProtocol"; |
4771 | 0 | DEBUGMSGTL(("usmUser", "%s %s\n", *errorMsg, buf)); |
4772 | 0 | goto fail; |
4773 | 0 | } |
4774 | 0 | DEBUGMSGTL(("9:usmUser", "privProtocol %s\n", buf)); |
4775 | 0 | pai = sc_get_priv_alg_bytype(priv_type); |
4776 | 0 | if (pai) { |
4777 | 0 | SNMP_FREE(newuser->privProtocol); |
4778 | 0 | newuser->privProtocolLen = pai->oid_len; |
4779 | 0 | newuser->privProtocol = |
4780 | 0 | snmp_duplicate_objid(pai->alg_oid, newuser->privProtocolLen); |
4781 | 0 | DEBUGMSGTL(("9:usmUser", "pai %s\n", pai->name)); |
4782 | 0 | if (newuser->privProtocol == NULL) { |
4783 | 0 | *errorMsg = "malloc failed"; |
4784 | 0 | goto fail; |
4785 | 0 | } |
4786 | 0 | } |
4787 | 0 | } |
4788 | 0 | if (NULL == pai) { |
4789 | 0 | *errorMsg = "priv protocol lookup failed"; |
4790 | 0 | goto fail; |
4791 | 0 | } |
4792 | | |
4793 | 0 | if (0 == newuser->privProtocol[0] && NULL == *errorMsg) |
4794 | 0 | *errorMsg = "Unknown privacy protocol"; |
4795 | 0 | if (NULL != *errorMsg) |
4796 | 0 | goto fail; |
4797 | | #ifdef NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV |
4798 | | if (snmp_oid_compare(newuser->privProtocol, newuser->privProtocolLen, |
4799 | | def_priv_prot, def_priv_prot_len) != 0) { |
4800 | | *errorMsg = "priv protocol does not match system policy"; |
4801 | | goto fail; |
4802 | | } |
4803 | | #endif /* NETSNMP_FORCE_SYSTEM_V3_AUTHPRIV */ |
4804 | | |
4805 | 0 | properPrivKeyLen = pai->proper_length; |
4806 | 0 | if (USM_CREATE_USER_PRIV_DES == pai->type) |
4807 | 0 | properPrivKeyLen *= 2; /* ?? we store salt with key */ |
4808 | | |
4809 | | /* |
4810 | | * READ: Encryption Pass Phrase or key |
4811 | | */ |
4812 | 0 | if (!cp) { |
4813 | | /* |
4814 | | * assume the same as the authentication key |
4815 | | */ |
4816 | 0 | newuser->privKey = netsnmp_memdup(newuser->authKey, |
4817 | 0 | newuser->authKeyLen); |
4818 | 0 | privKeySize = newuser->privKeyLen = newuser->authKeyLen; |
4819 | 0 | if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) { |
4820 | 0 | newuser->privKeyKu = netsnmp_memdup(newuser->authKeyKu, |
4821 | 0 | newuser->authKeyKuLen); |
4822 | 0 | newuser->privKeyKuLen = newuser->authKeyKuLen; |
4823 | 0 | } |
4824 | 0 | } else { |
4825 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4826 | | |
4827 | 0 | if (strcmp(buf,"-m") == 0) { |
4828 | | /* a master key is specified */ |
4829 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4830 | 0 | ret = sizeof(userKey); |
4831 | 0 | tmpp = userKey; |
4832 | 0 | userKeyLen = 0; |
4833 | 0 | if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) { |
4834 | 0 | *errorMsg = "invalid key value argument to -m"; |
4835 | 0 | goto fail; |
4836 | 0 | } |
4837 | | /* save master key */ |
4838 | 0 | if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) { |
4839 | 0 | newuser->privKeyKu = netsnmp_memdup(userKey, userKeyLen); |
4840 | 0 | newuser->privKeyKuLen = userKeyLen; |
4841 | 0 | } |
4842 | 0 | } else if (strcmp(buf,"-l") != 0) { |
4843 | | /* a password is specified */ |
4844 | 0 | userKeyLen = sizeof(userKey); |
4845 | 0 | ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen, |
4846 | 0 | (u_char*)buf, strlen(buf), userKey, &userKeyLen); |
4847 | 0 | if (ret2 != SNMPERR_SUCCESS) { |
4848 | 0 | *errorMsg = "could not generate the privacy key from the supplied pass phrase."; |
4849 | 0 | goto fail; |
4850 | 0 | } |
4851 | | /* save master key */ |
4852 | 0 | if (newuser->flags & USMUSER_FLAG_KEEP_MASTER_KEY) { |
4853 | 0 | newuser->privKeyKu = netsnmp_memdup(userKey, userKeyLen); |
4854 | 0 | newuser->privKeyKuLen = userKeyLen; |
4855 | 0 | } |
4856 | 0 | } |
4857 | | |
4858 | | /* |
4859 | | * And turn it into a localized key |
4860 | | * Allocate enough space for greater of auth mac and privKey len. |
4861 | | */ |
4862 | 0 | privKeySize = SNMP_MAX(properPrivKeyLen, properLen); |
4863 | 0 | newuser->privKey = (u_char *) malloc(privKeySize); |
4864 | 0 | newuser->privKeyLen = privKeySize; |
4865 | |
|
4866 | 0 | if (strcmp(buf,"-l") == 0) { |
4867 | | /* a local key is directly specified */ |
4868 | 0 | cp = copy_nword(cp, buf, sizeof(buf)); |
4869 | 0 | ret = newuser->privKeyLen; |
4870 | 0 | newuser->privKeyLen = 0; |
4871 | 0 | if (!snmp_hex_to_binary(&newuser->privKey, &ret, |
4872 | 0 | &newuser->privKeyLen, 0, buf)) { |
4873 | 0 | *errorMsg = "invalid key value argument to -l"; |
4874 | 0 | goto fail; |
4875 | 0 | } |
4876 | 0 | } else { |
4877 | 0 | ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen, |
4878 | 0 | newuser->engineID, newuser->engineIDLen, |
4879 | 0 | userKey, userKeyLen, |
4880 | 0 | newuser->privKey, &newuser->privKeyLen); |
4881 | 0 | if (ret2 != SNMPERR_SUCCESS) { |
4882 | 0 | *errorMsg = "could not generate localized privacy key (Kul) from the master key (Ku)."; |
4883 | 0 | goto fail; |
4884 | 0 | } |
4885 | 0 | } |
4886 | | |
4887 | 0 | if (newuser->privKeyLen < properPrivKeyLen) { |
4888 | 0 | ret = usm_extend_user_kul(newuser, properPrivKeyLen); |
4889 | 0 | if (ret != SNMPERR_SUCCESS) { |
4890 | 0 | *errorMsg = "could not extend localized privacy key to required length."; |
4891 | 0 | goto fail; |
4892 | 0 | } |
4893 | 0 | } |
4894 | 0 | } |
4895 | | |
4896 | 0 | if ((newuser->privKeyLen >= properPrivKeyLen) || (properPrivKeyLen == 0)){ |
4897 | 0 | DEBUGMSGTL(("9:usmUser", "truncating privKeyLen from %" NETSNMP_PRIz "d to %d\n", |
4898 | 0 | newuser->privKeyLen, properPrivKeyLen)); |
4899 | 0 | newuser->privKeyLen = properPrivKeyLen; |
4900 | 0 | } |
4901 | 0 | else { |
4902 | 0 | DEBUGMSGTL(("usmUser", |
4903 | 0 | "privKey length %" NETSNMP_PRIz "d < %d required by privProtocol\n", |
4904 | 0 | newuser->privKeyLen, properPrivKeyLen)); |
4905 | 0 | *errorMsg = "privKey length is less than required by privProtocol"; |
4906 | 0 | goto fail; |
4907 | 0 | } |
4908 | | |
4909 | 0 | add: |
4910 | 0 | usm_add_user(newuser); |
4911 | 0 | DEBUGMSGTL(("usmUser", "created a new user %s at ", newuser->secName)); |
4912 | 0 | DEBUGMSGHEX(("usmUser", newuser->engineID, newuser->engineIDLen)); |
4913 | 0 | DEBUGMSG(("usmUser", "\n")); |
4914 | |
|
4915 | 0 | return newuser; |
4916 | | |
4917 | 0 | fail: |
4918 | 0 | usm_free_user(newuser); |
4919 | 0 | return NULL; |
4920 | 0 | } |
4921 | | |
4922 | | void |
4923 | | usm_parse_create_usmUser(const char *token, char *line) |
4924 | 0 | { |
4925 | 0 | const char *error = NULL; |
4926 | 0 | usm_create_usmUser_from_string(line, &error); |
4927 | 0 | if (error) |
4928 | 0 | config_perror(error); |
4929 | 0 | } |
4930 | | |
4931 | | static void |
4932 | | snmpv3_authtype_conf(const char *word, char *cptr) |
4933 | 0 | { |
4934 | 0 | int auth_type = usm_lookup_auth_type(cptr); |
4935 | 0 | if (auth_type < 0) |
4936 | 0 | config_perror("Unknown authentication type"); |
4937 | 0 | defaultAuthType = sc_get_auth_oid(auth_type, &defaultAuthTypeLen); |
4938 | 0 | DEBUGMSGTL(("snmpv3", "set default authentication type: %s\n", cptr)); |
4939 | 0 | } |
4940 | | |
4941 | | const oid * |
4942 | | get_default_authtype(size_t * len) |
4943 | 0 | { |
4944 | 0 | if (defaultAuthType == NULL) { |
4945 | 0 | defaultAuthType = SNMP_DEFAULT_AUTH_PROTO; |
4946 | 0 | defaultAuthTypeLen = SNMP_DEFAULT_AUTH_PROTOLEN; |
4947 | 0 | } |
4948 | 0 | if (len) |
4949 | 0 | *len = defaultAuthTypeLen; |
4950 | 0 | return defaultAuthType; |
4951 | 0 | } |
4952 | | |
4953 | | static void |
4954 | | snmpv3_privtype_conf(const char *word, char *cptr) |
4955 | 0 | { |
4956 | 0 | int priv_type = usm_lookup_priv_type(cptr); |
4957 | 0 | if (priv_type < 0) |
4958 | 0 | config_perror("Unknown privacy type"); |
4959 | 0 | defaultPrivType = sc_get_priv_oid(priv_type, &defaultPrivTypeLen); |
4960 | 0 | DEBUGMSGTL(("snmpv3", "set default privacy type: %s\n", cptr)); |
4961 | 0 | } |
4962 | | |
4963 | | const oid * |
4964 | | get_default_privtype(size_t * len) |
4965 | 0 | { |
4966 | 0 | if (defaultPrivType == NULL) { |
4967 | 0 | defaultPrivType = SNMP_DEFAULT_PRIV_PROTO; |
4968 | 0 | defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN; |
4969 | 0 | } |
4970 | 0 | if (len) |
4971 | 0 | *len = defaultPrivTypeLen; |
4972 | 0 | return defaultPrivType; |
4973 | 0 | } |
4974 | | |
4975 | | void |
4976 | | init_usm_conf(const char *app) |
4977 | 0 | { |
4978 | 0 | register_config_handler(app, "usmUser", |
4979 | 0 | usm_parse_config_usmUser, NULL, NULL); |
4980 | 0 | register_config_handler(app, "createUser", |
4981 | 0 | usm_parse_create_usmUser, NULL, |
4982 | 0 | "username [-e ENGINEID] (MD5|SHA|SHA-512|SHA-384|SHA-256|SHA-224|default) authpassphrase [(DES|AES|default) [privpassphrase]]"); |
4983 | | |
4984 | | /* |
4985 | | * we need to be called back later |
4986 | | */ |
4987 | 0 | snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, |
4988 | 0 | usm_store_users, NULL); |
4989 | 0 | } |
4990 | | |
4991 | | /* |
4992 | | * initializations for the USM. |
4993 | | * |
4994 | | * Should be called after the (engineid) configuration files have been read. |
4995 | | * |
4996 | | * Set "arbitrary" portion of salt to a random number. |
4997 | | */ |
4998 | | static int |
4999 | | init_usm_post_config(int majorid, int minorid, void *serverarg, |
5000 | | void *clientarg) |
5001 | 0 | { |
5002 | 0 | size_t salt_integer_len = sizeof(salt_integer); |
5003 | |
|
5004 | 0 | if (sc_random((u_char *) & salt_integer, &salt_integer_len) != |
5005 | 0 | SNMPERR_SUCCESS) { |
5006 | 0 | DEBUGMSGTL(("usm", "sc_random() failed: using time() as salt.\n")); |
5007 | 0 | salt_integer = (u_int) time(NULL); |
5008 | 0 | } |
5009 | |
|
5010 | 0 | #ifdef HAVE_AES |
5011 | 0 | salt_integer_len = sizeof (salt_integer64_1); |
5012 | 0 | if (sc_random((u_char *) & salt_integer64_1, &salt_integer_len) != |
5013 | 0 | SNMPERR_SUCCESS) { |
5014 | 0 | DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes1 salt.\n")); |
5015 | 0 | salt_integer64_1 = (u_int) time(NULL); |
5016 | 0 | } |
5017 | 0 | salt_integer_len = sizeof (salt_integer64_1); |
5018 | 0 | if (sc_random((u_char *) & salt_integer64_2, &salt_integer_len) != |
5019 | 0 | SNMPERR_SUCCESS) { |
5020 | 0 | DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes2 salt.\n")); |
5021 | 0 | salt_integer64_2 = (u_int) time(NULL); |
5022 | 0 | } |
5023 | 0 | #endif |
5024 | |
|
5025 | 0 | #ifndef NETSNMP_DISABLE_MD5 |
5026 | 0 | noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol, |
5027 | 0 | OID_LENGTH(usmHMACMD5AuthProtocol), |
5028 | 0 | SNMP_DEFAULT_PRIV_PROTO, |
5029 | 0 | SNMP_DEFAULT_PRIV_PROTOLEN); |
5030 | | #else |
5031 | | noNameUser = usm_create_initial_user("", usmHMACSHA1AuthProtocol, |
5032 | | OID_LENGTH(usmHMACSHA1AuthProtocol), |
5033 | | SNMP_DEFAULT_PRIV_PROTO, |
5034 | | SNMP_DEFAULT_PRIV_PROTOLEN); |
5035 | | #endif |
5036 | |
|
5037 | 0 | if ( noNameUser ) { |
5038 | 0 | SNMP_FREE(noNameUser->engineID); |
5039 | 0 | noNameUser->engineIDLen = 0; |
5040 | 0 | } |
5041 | |
|
5042 | 0 | return SNMPERR_SUCCESS; |
5043 | 0 | } /* end init_usm_post_config() */ |
5044 | | |
5045 | | static int |
5046 | | deinit_usm_post_config(int majorid, int minorid, void *serverarg, |
5047 | | void *clientarg) |
5048 | 0 | { |
5049 | 0 | if (usm_free_user(noNameUser) != NULL) { |
5050 | 0 | DEBUGMSGTL(("deinit_usm_post_config", "could not free initial user\n")); |
5051 | 0 | return SNMPERR_GENERR; |
5052 | 0 | } |
5053 | 0 | noNameUser = NULL; |
5054 | |
|
5055 | 0 | DEBUGMSGTL(("deinit_usm_post_config", "initial user removed\n")); |
5056 | 0 | return SNMPERR_SUCCESS; |
5057 | 0 | } /* end deinit_usm_post_config() */ |
5058 | | |
5059 | | void |
5060 | | init_usm(void) |
5061 | 0 | { |
5062 | 0 | struct snmp_secmod_def *def; |
5063 | 0 | char *type; |
5064 | |
|
5065 | 0 | DEBUGMSGTL(("init_usm", "unit_usm: %" NETSNMP_PRIo "u %" NETSNMP_PRIo "u\n", |
5066 | 0 | usmNoPrivProtocol[0], usmNoPrivProtocol[1])); |
5067 | |
|
5068 | 0 | sc_init(); /* initalize scapi code */ |
5069 | | |
5070 | | /* |
5071 | | * register ourselves as a security service |
5072 | | */ |
5073 | 0 | def = SNMP_MALLOC_STRUCT(snmp_secmod_def); |
5074 | 0 | if (def == NULL) |
5075 | 0 | return; |
5076 | | /* |
5077 | | * XXX: def->init_sess_secmod move stuff from snmp_api.c |
5078 | | */ |
5079 | 0 | def->encode_reverse = usm_secmod_rgenerate_out_msg; |
5080 | 0 | def->encode_forward = usm_secmod_generate_out_msg; |
5081 | 0 | def->decode = usm_secmod_process_in_msg; |
5082 | 0 | def->pdu_clone = usm_clone; |
5083 | 0 | def->pdu_free_state_ref = usm_free_usmStateReference; |
5084 | 0 | def->session_setup = usm_session_init; |
5085 | 0 | def->handle_report = usm_handle_report; |
5086 | 0 | def->probe_engineid = usm_discover_engineid; |
5087 | 0 | def->post_probe_engineid = usm_create_user_from_session_hook; |
5088 | 0 | if (register_sec_mod(USM_SEC_MODEL_NUMBER, "usm", def) != SNMPERR_SUCCESS) { |
5089 | 0 | SNMP_FREE(def); |
5090 | 0 | snmp_log(LOG_ERR, "could not register usm sec mod\n"); |
5091 | 0 | return; |
5092 | 0 | } |
5093 | | |
5094 | 0 | snmp_register_callback(SNMP_CALLBACK_LIBRARY, |
5095 | 0 | SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, |
5096 | 0 | init_usm_post_config, NULL); |
5097 | |
|
5098 | 0 | snmp_register_callback(SNMP_CALLBACK_LIBRARY, |
5099 | 0 | SNMP_CALLBACK_SHUTDOWN, |
5100 | 0 | deinit_usm_post_config, NULL); |
5101 | |
|
5102 | 0 | snmp_register_callback(SNMP_CALLBACK_LIBRARY, |
5103 | 0 | SNMP_CALLBACK_SHUTDOWN, |
5104 | 0 | free_engineID, NULL); |
5105 | |
|
5106 | 0 | register_config_handler("snmp", "defAuthType", snmpv3_authtype_conf, |
5107 | 0 | NULL, "MD5|SHA|SHA-512|SHA-384|SHA-256|SHA-224"); |
5108 | 0 | register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf, |
5109 | 0 | NULL, |
5110 | 0 | "DES" |
5111 | 0 | #ifdef HAVE_AES |
5112 | 0 | "|AES|AES-128" |
5113 | 0 | #ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04 |
5114 | 0 | "|AES-192|AES-256" |
5115 | 0 | #endif /* NETSNMP_DRAFT_BLUMENTHAL_AES_04 */ |
5116 | | #else |
5117 | | " (AES support not available)" |
5118 | | #endif |
5119 | 0 | ); |
5120 | | |
5121 | | /* |
5122 | | * Free stuff at shutdown time |
5123 | | */ |
5124 | 0 | snmp_register_callback(SNMP_CALLBACK_LIBRARY, |
5125 | 0 | SNMP_CALLBACK_SHUTDOWN, |
5126 | 0 | free_enginetime_on_shutdown, NULL); |
5127 | | |
5128 | |
|
5129 | 0 | type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE); |
5130 | |
|
5131 | 0 | register_config_handler(type, "userSetAuthPass", usm_set_password, |
5132 | 0 | NULL, NULL); |
5133 | 0 | register_config_handler(type, "userSetPrivPass", usm_set_password, |
5134 | 0 | NULL, NULL); |
5135 | 0 | register_config_handler(type, "userSetAuthKey", usm_set_password, NULL, |
5136 | 0 | NULL); |
5137 | 0 | register_config_handler(type, "userSetPrivKey", usm_set_password, NULL, |
5138 | 0 | NULL); |
5139 | 0 | register_config_handler(type, "userSetAuthLocalKey", usm_set_password, |
5140 | 0 | NULL, NULL); |
5141 | 0 | register_config_handler(type, "userSetPrivLocalKey", usm_set_password, |
5142 | 0 | NULL, NULL); |
5143 | 0 | } |
5144 | | |
5145 | | void |
5146 | | shutdown_usm(void) |
5147 | 0 | { |
5148 | 0 | free_etimelist(); |
5149 | 0 | clear_user_list(); |
5150 | 0 | } |