net-snmp
5.4.1
|
00001 /* Portions of this file are subject to the following copyright(s). See 00002 * the Net-SNMP's COPYING file for more details and other copyrights 00003 * that may apply: 00004 */ 00005 /* 00006 * Portions of this file are copyrighted by: 00007 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00008 * Use is subject to license terms specified in the COPYING file 00009 * distributed with the Net-SNMP package. 00010 */ 00011 /* 00012 * snmpusm.c 00013 * 00014 * Routines to manipulate a information about a "user" as 00015 * defined by the SNMP-USER-BASED-SM-MIB MIB. 00016 * 00017 * All functions usm_set_usmStateReference_*() return 0 on success, -1 00018 * otherwise. 00019 * 00020 * !! Tab stops set to 4 in some parts of this file. !! 00021 * (Designated on a per function.) 00022 */ 00023 00024 #include <net-snmp/net-snmp-config.h> 00025 00026 #include <sys/types.h> 00027 #if HAVE_WINSOCK_H 00028 #include <winsock.h> 00029 #endif 00030 #include <stdio.h> 00031 #ifdef HAVE_STDLIB_H 00032 #include <stdlib.h> 00033 #endif 00034 #if TIME_WITH_SYS_TIME 00035 # ifdef WIN32 00036 # include <sys/timeb.h> 00037 # else 00038 # include <sys/time.h> 00039 # endif 00040 # include <time.h> 00041 #else 00042 # if HAVE_SYS_TIME_H 00043 # include <sys/time.h> 00044 # else 00045 # include <time.h> 00046 # endif 00047 #endif 00048 #if HAVE_STRING_H 00049 #include <string.h> 00050 #else 00051 #include <strings.h> 00052 #endif 00053 #ifdef HAVE_NETINET_IN_H 00054 #include <netinet/in.h> 00055 #endif 00056 00057 #if HAVE_DMALLOC_H 00058 #include <dmalloc.h> 00059 #endif 00060 00061 #include <net-snmp/types.h> 00062 #include <net-snmp/output_api.h> 00063 #include <net-snmp/config_api.h> 00064 #include <net-snmp/utilities.h> 00065 00066 #include <net-snmp/library/asn1.h> 00067 #include <net-snmp/library/snmp_api.h> 00068 #include <net-snmp/library/callback.h> 00069 #include <net-snmp/library/tools.h> 00070 #include <net-snmp/library/keytools.h> 00071 #include <net-snmp/library/snmpv3.h> 00072 #include <net-snmp/library/lcd_time.h> 00073 #include <net-snmp/library/scapi.h> 00074 #include <net-snmp/library/callback.h> 00075 #include <net-snmp/library/snmp_secmod.h> 00076 #include <net-snmp/library/snmpusm.h> 00077 00078 oid usmNoAuthProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 1, 1 }; 00079 #ifndef NETSNMP_DISABLE_MD5 00080 oid usmHMACMD5AuthProtocol[10] = 00081 { 1, 3, 6, 1, 6, 3, 10, 1, 1, 2 }; 00082 #endif 00083 oid usmHMACSHA1AuthProtocol[10] = 00084 { 1, 3, 6, 1, 6, 3, 10, 1, 1, 3 }; 00085 oid usmNoPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 }; 00086 #ifndef NETSNMP_DISABLE_DES 00087 oid usmDESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 }; 00088 #endif 00089 oid usmAESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 4 }; 00090 /* backwards compat */ 00091 oid *usmAES128PrivProtocol = usmAESPrivProtocol; 00092 00093 static u_int dummy_etime, dummy_eboot; /* For ISENGINEKNOWN(). */ 00094 00095 /* 00096 * Globals. 00097 */ 00098 static u_int salt_integer; 00099 #ifdef HAVE_AES 00100 static u_int salt_integer64_1, salt_integer64_2; 00101 #endif 00102 /* 00103 * 1/2 of seed for the salt. Cf. RFC2274, Sect 8.1.1.1. 00104 */ 00105 00106 static struct usmUser *noNameUser = NULL; 00107 /* 00108 * Local storage (LCD) of the default user list. 00109 */ 00110 static struct usmUser *userList = NULL; 00111 00112 /* 00113 * Prototypes 00114 */ 00115 int 00116 usm_check_secLevel_vs_protocols(int level, 00117 const oid * authProtocol, 00118 u_int authProtocolLen, 00119 const oid * privProtocol, 00120 u_int privProtocolLen); 00121 int 00122 usm_calc_offsets(size_t globalDataLen, 00123 int secLevel, size_t secEngineIDLen, 00124 size_t secNameLen, size_t scopedPduLen, 00125 u_long engineboots, long engine_time, 00126 size_t * theTotalLength, 00127 size_t * authParamsOffset, 00128 size_t * privParamsOffset, 00129 size_t * dataOffset, size_t * datalen, 00130 size_t * msgAuthParmLen, 00131 size_t * msgPrivParmLen, size_t * otstlen, 00132 size_t * seq_len, size_t * msgSecParmLen); 00133 /* 00134 * Set a given field of the secStateRef. 00135 * 00136 * Allocate <len> bytes for type <type> pointed to by ref-><field>. 00137 * Then copy in <item> and record its length in ref-><field_len>. 00138 * 00139 * Return 0 on success, -1 otherwise. 00140 */ 00141 #define MAKE_ENTRY( type, item, len, field, field_len ) \ 00142 { \ 00143 if (ref == NULL) \ 00144 return -1; \ 00145 if (ref->field != NULL) { \ 00146 SNMP_ZERO(ref->field, ref->field_len); \ 00147 SNMP_FREE(ref->field); \ 00148 } \ 00149 ref->field_len = 0; \ 00150 if (len == 0 || item == NULL) { \ 00151 return 0; \ 00152 } \ 00153 if ((ref->field = (type*) malloc (len * sizeof(type))) == NULL) \ 00154 { \ 00155 return -1; \ 00156 } \ 00157 \ 00158 memcpy (ref->field, item, len * sizeof(type)); \ 00159 ref->field_len = len; \ 00160 \ 00161 return 0; \ 00162 } 00163 00164 00165 struct usmStateReference * 00166 usm_malloc_usmStateReference(void) 00167 { 00168 struct usmStateReference *retval = (struct usmStateReference *) 00169 calloc(1, sizeof(struct usmStateReference)); 00170 00171 return retval; 00172 } /* end usm_malloc_usmStateReference() */ 00173 00174 00175 void 00176 usm_free_usmStateReference(void *old) 00177 { 00178 struct usmStateReference *old_ref = (struct usmStateReference *) old; 00179 00180 if (old_ref) { 00181 00182 SNMP_FREE(old_ref->usr_name); 00183 SNMP_FREE(old_ref->usr_engine_id); 00184 SNMP_FREE(old_ref->usr_auth_protocol); 00185 SNMP_FREE(old_ref->usr_priv_protocol); 00186 00187 if (old_ref->usr_auth_key) { 00188 SNMP_ZERO(old_ref->usr_auth_key, old_ref->usr_auth_key_length); 00189 SNMP_FREE(old_ref->usr_auth_key); 00190 } 00191 if (old_ref->usr_priv_key) { 00192 SNMP_ZERO(old_ref->usr_priv_key, old_ref->usr_priv_key_length); 00193 SNMP_FREE(old_ref->usr_priv_key); 00194 } 00195 00196 SNMP_ZERO(old_ref, sizeof(*old_ref)); 00197 SNMP_FREE(old_ref); 00198 00199 } 00200 00201 } /* end usm_free_usmStateReference() */ 00202 00203 struct usmUser * 00204 usm_get_userList(void) 00205 { 00206 return userList; 00207 } 00208 00209 int 00210 usm_set_usmStateReference_name(struct usmStateReference *ref, 00211 char *name, size_t name_len) 00212 { 00213 MAKE_ENTRY(char, name, name_len, usr_name, usr_name_length); 00214 } 00215 00216 int 00217 usm_set_usmStateReference_engine_id(struct usmStateReference *ref, 00218 u_char * engine_id, 00219 size_t engine_id_len) 00220 { 00221 MAKE_ENTRY(u_char, engine_id, engine_id_len, 00222 usr_engine_id, usr_engine_id_length); 00223 } 00224 00225 int 00226 usm_set_usmStateReference_auth_protocol(struct usmStateReference *ref, 00227 oid * auth_protocol, 00228 size_t auth_protocol_len) 00229 { 00230 MAKE_ENTRY(oid, auth_protocol, auth_protocol_len, 00231 usr_auth_protocol, usr_auth_protocol_length); 00232 } 00233 00234 int 00235 usm_set_usmStateReference_auth_key(struct usmStateReference *ref, 00236 u_char * auth_key, size_t auth_key_len) 00237 { 00238 MAKE_ENTRY(u_char, auth_key, auth_key_len, 00239 usr_auth_key, usr_auth_key_length); 00240 } 00241 00242 int 00243 usm_set_usmStateReference_priv_protocol(struct usmStateReference *ref, 00244 oid * priv_protocol, 00245 size_t priv_protocol_len) 00246 { 00247 MAKE_ENTRY(oid, priv_protocol, priv_protocol_len, 00248 usr_priv_protocol, usr_priv_protocol_length); 00249 } 00250 00251 int 00252 usm_set_usmStateReference_priv_key(struct usmStateReference *ref, 00253 u_char * priv_key, size_t priv_key_len) 00254 { 00255 MAKE_ENTRY(u_char, priv_key, priv_key_len, 00256 usr_priv_key, usr_priv_key_length); 00257 } 00258 00259 int 00260 usm_set_usmStateReference_sec_level(struct usmStateReference *ref, 00261 int sec_level) 00262 { 00263 if (ref == NULL) 00264 return -1; 00265 ref->usr_sec_level = sec_level; 00266 return 0; 00267 } 00268 00269 00270 00271 #ifdef NETSNMP_ENABLE_TESTING_CODE 00272 /*******************************************************************-o-****** 00273 * emergency_print 00274 * 00275 * Parameters: 00276 * *field 00277 * length 00278 * 00279 * This is a print routine that is solely included so that it can be 00280 * used in gdb. Don't use it as a function, it will be pulled before 00281 * a real release of the code. 00282 * 00283 * tab stop 4 00284 * 00285 * XXX fflush() only works on FreeBSD; core dumps on Sun OS's 00286 */ 00287 void 00288 emergency_print(u_char * field, u_int length) 00289 { 00290 int iindex; 00291 int start = 0; 00292 int stop = 25; 00293 00294 while (start < stop) { 00295 for (iindex = start; iindex < stop; iindex++) 00296 printf("%02X ", field[iindex]); 00297 00298 printf("\n"); 00299 start = stop; 00300 stop = stop + 25 < length ? stop + 25 : length; 00301 } 00302 fflush(0); 00303 00304 } /* end emergency_print() */ 00305 #endif /* NETSNMP_ENABLE_TESTING_CODE */ 00306 00307 00308 /*******************************************************************-o-****** 00309 * asn_predict_int_length 00310 * 00311 * Parameters: 00312 * type (UNUSED) 00313 * number 00314 * len 00315 * 00316 * Returns: 00317 * Number of bytes necessary to store the ASN.1 encoded value of 'number'. 00318 * 00319 * 00320 * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will 00321 * use to encode a particular integer value. 00322 * 00323 * Returns the length of the integer -- NOT THE HEADER! 00324 * 00325 * Do this the same way as asn_build_int()... 00326 */ 00327 int 00328 asn_predict_int_length(int type, long number, size_t len) 00329 { 00330 register u_long mask; 00331 00332 00333 if (len != sizeof(long)) 00334 return -1; 00335 00336 mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1); 00337 /* 00338 * mask is 0xFF800000 on a big-endian machine 00339 */ 00340 00341 while ((((number & mask) == 0) || ((number & mask) == mask)) 00342 && len > 1) { 00343 len--; 00344 number <<= 8; 00345 } 00346 00347 return len; 00348 00349 } /* end asn_predict_length() */ 00350 00351 00352 00353 00354 /*******************************************************************-o-****** 00355 * asn_predict_length 00356 * 00357 * Parameters: 00358 * type 00359 * *ptr 00360 * u_char_len 00361 * 00362 * Returns: 00363 * Length in bytes: 1 + <n> + <u_char_len>, where 00364 * 00365 * 1 For the ASN.1 type. 00366 * <n> # of bytes to store length of data. 00367 * <u_char_len> Length of data associated with ASN.1 type. 00368 * 00369 * This gives the number of bytes that the ASN.1 encoder (in asn1.c) will 00370 * use to encode a particular integer value. This is as broken as the 00371 * currently used encoder. 00372 * 00373 * XXX How is <n> chosen, exactly?? 00374 */ 00375 int 00376 asn_predict_length(int type, u_char * ptr, size_t u_char_len) 00377 { 00378 00379 if (type & ASN_SEQUENCE) 00380 return 1 + 3 + u_char_len; 00381 00382 if (type & ASN_INTEGER) { 00383 u_long value; 00384 memcpy(&value, ptr, u_char_len); 00385 u_char_len = asn_predict_int_length(type, value, u_char_len); 00386 } 00387 00388 if (u_char_len < 0x80) 00389 return 1 + 1 + u_char_len; 00390 else if (u_char_len < 0xFF) 00391 return 1 + 2 + u_char_len; 00392 else 00393 return 1 + 3 + u_char_len; 00394 00395 } /* end asn_predict_length() */ 00396 00397 00398 00399 00400 /*******************************************************************-o-****** 00401 * usm_calc_offsets 00402 * 00403 * Parameters: 00404 * (See list below...) 00405 * 00406 * Returns: 00407 * 0 On success, 00408 * -1 Otherwise. 00409 * 00410 * 00411 * This routine calculates the offsets into an outgoing message buffer 00412 * for the necessary values. The outgoing buffer will generically 00413 * look like this: 00414 * 00415 * SNMPv3 Message 00416 * SEQ len[11] 00417 * INT len version 00418 * Header 00419 * SEQ len 00420 * INT len MsgID 00421 * INT len msgMaxSize 00422 * OST len msgFlags (OST = OCTET STRING) 00423 * INT len msgSecurityModel 00424 * MsgSecurityParameters 00425 * [1] OST len[2] 00426 * SEQ len[3] 00427 * OST len msgAuthoritativeEngineID 00428 * INT len msgAuthoritativeEngineBoots 00429 * INT len msgAuthoritativeEngineTime 00430 * OST len msgUserName 00431 * OST len[4] [5] msgAuthenticationParameters 00432 * OST len[6] [7] msgPrivacyParameters 00433 * MsgData 00434 * [8] OST len[9] [10] encryptedPDU 00435 * or 00436 * [8,10] SEQUENCE len[9] scopedPDU 00437 * [12] 00438 * 00439 * The bracketed points will be needed to be identified ([x] is an index 00440 * value, len[x] means a length value). Here is a semantic guide to them: 00441 * 00442 * [1] = globalDataLen (input) 00443 * [2] = otstlen 00444 * [3] = seq_len 00445 * [4] = msgAuthParmLen (may be 0 or 12) 00446 * [5] = authParamsOffset 00447 * [6] = msgPrivParmLen (may be 0 or 8) 00448 * [7] = privParamsOffset 00449 * [8] = globalDataLen + msgSecParmLen 00450 * [9] = datalen 00451 * [10] = dataOffset 00452 * [11] = theTotalLength - the length of the header itself 00453 * [12] = theTotalLength 00454 */ 00455 int 00456 usm_calc_offsets(size_t globalDataLen, /* SNMPv3Message + HeaderData */ 00457 int secLevel, size_t secEngineIDLen, size_t secNameLen, size_t scopedPduLen, /* An BER encoded sequence. */ 00458 u_long engineboots, /* XXX (asn1.c works in long, not int.) */ 00459 long engine_time, /* XXX (asn1.c works in long, not int.) */ 00460 size_t * theTotalLength, /* globalDataLen + msgSecurityP. + msgData */ 00461 size_t * authParamsOffset, /* Distance to auth bytes. */ 00462 size_t * privParamsOffset, /* Distance to priv bytes. */ 00463 size_t * dataOffset, /* Distance to scopedPdu SEQ -or- the 00464 * crypted (data) portion of msgData. */ 00465 size_t * datalen, /* Size of msgData OCTET STRING encoding. */ 00466 size_t * msgAuthParmLen, /* Size of msgAuthenticationParameters. */ 00467 size_t * msgPrivParmLen, /* Size of msgPrivacyParameters. */ 00468 size_t * otstlen, /* Size of msgSecurityP. O.S. encoding. */ 00469 size_t * seq_len, /* Size of msgSecurityP. SEQ data. */ 00470 size_t * msgSecParmLen) 00471 { /* Size of msgSecurityP. SEQ. */ 00472 int engIDlen, /* Sizes of OCTET STRING and SEQ encodings */ 00473 engBtlen, /* for fields within */ 00474 engTmlen, /* msgSecurityParameters portion of */ 00475 namelen, /* SNMPv3Message. */ 00476 authlen, privlen; 00477 00478 /* 00479 * If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0. 00480 * If doing encryption, msgPrivParmLen = 8 else msgPrivParmLen = 0. 00481 */ 00482 *msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV 00483 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 12 : 0; 00484 00485 *msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) ? 8 : 0; 00486 00487 00488 /* 00489 * Calculate lengths. 00490 */ 00491 if ((engIDlen = asn_predict_length(ASN_OCTET_STR, 00492 0, secEngineIDLen)) == -1) { 00493 return -1; 00494 } 00495 00496 if ((engBtlen = asn_predict_length(ASN_INTEGER, 00497 (u_char *) & engineboots, 00498 sizeof(long))) == -1) { 00499 return -1; 00500 } 00501 00502 if ((engTmlen = asn_predict_length(ASN_INTEGER, 00503 (u_char *) & engine_time, 00504 sizeof(long))) == -1) { 00505 return -1; 00506 } 00507 00508 if ((namelen = asn_predict_length(ASN_OCTET_STR, 0, secNameLen)) == -1) { 00509 return -1; 00510 } 00511 00512 if ((authlen = asn_predict_length(ASN_OCTET_STR, 00513 0, *msgAuthParmLen)) == -1) { 00514 return -1; 00515 } 00516 00517 if ((privlen = asn_predict_length(ASN_OCTET_STR, 00518 0, *msgPrivParmLen)) == -1) { 00519 return -1; 00520 } 00521 00522 *seq_len = 00523 engIDlen + engBtlen + engTmlen + namelen + authlen + privlen; 00524 00525 if ((*otstlen = asn_predict_length(ASN_SEQUENCE, 0, *seq_len)) == -1) { 00526 return -1; 00527 } 00528 00529 if ((*msgSecParmLen = asn_predict_length(ASN_OCTET_STR, 00530 0, *otstlen)) == -1) { 00531 return -1; 00532 } 00533 00534 *authParamsOffset = globalDataLen + +(*msgSecParmLen - *seq_len) 00535 + engIDlen + engBtlen + engTmlen + namelen 00536 + (authlen - *msgAuthParmLen); 00537 00538 *privParamsOffset = *authParamsOffset + *msgAuthParmLen 00539 + (privlen - *msgPrivParmLen); 00540 00541 00542 /* 00543 * Compute the size of the plaintext. Round up to account for cipher 00544 * block size, if necessary. 00545 * 00546 * XXX This is hardwired for 1DES... If scopedPduLen is already 00547 * a multiple of 8, then *add* 8 more; otherwise, round up 00548 * to the next multiple of 8. 00549 * 00550 * FIX Calculation of encrypted portion of msgData and consequent 00551 * setting and sanity checking of theTotalLength, et al. should 00552 * occur *after* encryption has taken place. 00553 */ 00554 if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 00555 scopedPduLen = ROUNDUP8(scopedPduLen); 00556 00557 if ((*datalen = 00558 asn_predict_length(ASN_OCTET_STR, 0, scopedPduLen)) == -1) { 00559 return -1; 00560 } 00561 } else { 00562 *datalen = scopedPduLen; 00563 } 00564 00565 *dataOffset = globalDataLen + *msgSecParmLen + 00566 (*datalen - scopedPduLen); 00567 *theTotalLength = globalDataLen + *msgSecParmLen + *datalen; 00568 00569 return 0; 00570 00571 } /* end usm_calc_offsets() */ 00572 00573 00574 00575 00576 00577 #ifndef NETSNMP_DISABLE_DES 00578 /*******************************************************************-o-****** 00579 * usm_set_salt 00580 * 00581 * Parameters: 00582 * *iv (O) Buffer to contain IV. 00583 * *iv_length (O) Length of iv. 00584 * *priv_salt (I) Salt portion of private key. 00585 * priv_salt_length (I) Length of priv_salt. 00586 * *msgSalt (I/O) Pointer salt portion of outgoing msg buffer. 00587 * 00588 * Returns: 00589 * 0 On success, 00590 * -1 Otherwise. 00591 * 00592 * Determine the initialization vector for the DES-CBC encryption. 00593 * (Cf. RFC 2274, 8.1.1.1.) 00594 * 00595 * iv is defined as the concatenation of engineBoots and the 00596 * salt integer. 00597 * The salt integer is incremented. 00598 * The resulting salt is copied into the msgSalt buffer. 00599 * The result of the concatenation is then XORed with the salt 00600 * portion of the private key (last 8 bytes). 00601 * The IV result is returned individually for further use. 00602 */ 00603 int 00604 usm_set_salt(u_char * iv, 00605 size_t * iv_length, 00606 u_char * priv_salt, size_t priv_salt_length, u_char * msgSalt) 00607 { 00608 size_t propersize_salt = BYTESIZE(USM_DES_SALT_LENGTH); 00609 int net_boots; 00610 int net_salt_int; 00611 /* 00612 * net_* should be encoded in network byte order. XXX Why? 00613 */ 00614 int iindex; 00615 00616 00617 /* 00618 * Sanity check. 00619 */ 00620 if (!iv || !iv_length || !priv_salt || (*iv_length != propersize_salt) 00621 || (priv_salt_length < propersize_salt)) { 00622 return -1; 00623 } 00624 00625 00626 net_boots = htonl(snmpv3_local_snmpEngineBoots()); 00627 net_salt_int = htonl(salt_integer); 00628 00629 salt_integer += 1; 00630 00631 memcpy(iv, &net_boots, propersize_salt / 2); 00632 memcpy(iv + (propersize_salt / 2), &net_salt_int, propersize_salt / 2); 00633 00634 if (msgSalt) 00635 memcpy(msgSalt, iv, propersize_salt); 00636 00637 00638 /* 00639 * Turn the salt into an IV: XOR <boots, salt_int> with salt 00640 * portion of priv_key. 00641 */ 00642 for (iindex = 0; iindex < (int) propersize_salt; iindex++) 00643 iv[iindex] ^= priv_salt[iindex]; 00644 00645 00646 return 0; 00647 00648 } /* end usm_set_salt() */ 00649 #endif 00650 00651 #ifdef HAVE_AES 00652 /*******************************************************************-o-****** 00653 * usm_set_aes_iv 00654 * 00655 * Parameters: 00656 * *iv (O) Buffer to contain IV. 00657 * *iv_length (O) Length of iv. 00658 * net_boots (I) the network byte order of the authEng boots val 00659 * net_time (I) the network byte order of the authEng time val 00660 * *salt (O) A buffer for the outgoing salt (= 8 bytes of iv) 00661 * 00662 * Returns: 00663 * 0 On success, 00664 * -1 Otherwise. 00665 * 00666 * Determine the initialization vector for AES encryption. 00667 * (draft-blumenthal-aes-usm-03.txt, 3.1.2.2) 00668 * 00669 * iv is defined as the concatenation of engineBoots, engineTime 00670 and a 64 bit salt-integer. 00671 * The 64 bit salt integer is incremented. 00672 * The resulting salt is copied into the salt buffer. 00673 * The IV result is returned individually for further use. 00674 */ 00675 int 00676 usm_set_aes_iv(u_char * iv, 00677 size_t * iv_length, 00678 u_int net_boots, 00679 u_int net_time, 00680 u_char * salt) 00681 { 00682 /* 00683 * net_* should be encoded in network byte order. 00684 */ 00685 int net_salt_int1, net_salt_int2; 00686 #define PROPER_AES_IV_SIZE 64 00687 00688 /* 00689 * Sanity check. 00690 */ 00691 if (!iv || !iv_length) { 00692 return -1; 00693 } 00694 00695 net_salt_int1 = htonl(salt_integer64_1); 00696 net_salt_int2 = htonl(salt_integer64_2); 00697 00698 if ((salt_integer64_2 += 1) == 0) 00699 salt_integer64_2 += 1; 00700 00701 /* XXX: warning: hard coded proper lengths */ 00702 memcpy(iv, &net_boots, 4); 00703 memcpy(iv+4, &net_time, 4); 00704 memcpy(iv+8, &net_salt_int1, 4); 00705 memcpy(iv+12, &net_salt_int2, 4); 00706 00707 memcpy(salt, iv+8, 8); /* only copy the needed portion */ 00708 return 0; 00709 } /* end usm_set_salt() */ 00710 #endif /* HAVE_AES */ 00711 00712 int 00713 usm_secmod_generate_out_msg(struct snmp_secmod_outgoing_params *parms) 00714 { 00715 if (!parms) 00716 return SNMPERR_GENERR; 00717 00718 return usm_generate_out_msg(parms->msgProcModel, 00719 parms->globalData, parms->globalDataLen, 00720 parms->maxMsgSize, parms->secModel, 00721 parms->secEngineID, parms->secEngineIDLen, 00722 parms->secName, parms->secNameLen, 00723 parms->secLevel, 00724 parms->scopedPdu, parms->scopedPduLen, 00725 parms->secStateRef, 00726 parms->secParams, parms->secParamsLen, 00727 parms->wholeMsg, parms->wholeMsgLen); 00728 } 00729 00730 /*******************************************************************-o-****** 00731 * usm_generate_out_msg 00732 * 00733 * Parameters: 00734 * (See list below...) 00735 * 00736 * Returns: 00737 * SNMPERR_SUCCESS On success. 00738 * SNMPERR_USM_AUTHENTICATIONFAILURE 00739 * SNMPERR_USM_ENCRYPTIONERROR 00740 * SNMPERR_USM_GENERICERROR 00741 * SNMPERR_USM_UNKNOWNSECURITYNAME 00742 * SNMPERR_USM_GENERICERROR 00743 * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL 00744 * 00745 * 00746 * Generates an outgoing message. 00747 * 00748 * XXX Beware of misnomers! 00749 */ 00750 int 00751 usm_generate_out_msg(int msgProcModel, /* (UNUSED) */ 00752 u_char * globalData, /* IN */ 00753 /* 00754 * Pointer to msg header data will point to the beginning 00755 * * of the entire packet buffer to be transmitted on wire, 00756 * * memory will be contiguous with secParams, typically 00757 * * this pointer will be passed back as beginning of 00758 * * wholeMsg below. asn seq. length is updated w/ new length. 00759 * * 00760 * * While this points to a buffer that should be big enough 00761 * * for the whole message, only the first two parts 00762 * * of the message are completed, namely SNMPv3Message and 00763 * * HeaderData. globalDataLen (next parameter) represents 00764 * * the length of these two completed parts. 00765 */ 00766 size_t globalDataLen, /* IN - Length of msg header data. */ 00767 int maxMsgSize, /* (UNUSED) */ 00768 int secModel, /* (UNUSED) */ 00769 u_char * secEngineID, /* IN - Pointer snmpEngineID. */ 00770 size_t secEngineIDLen, /* IN - SnmpEngineID length. */ 00771 char *secName, /* IN - Pointer to securityName. */ 00772 size_t secNameLen, /* IN - SecurityName length. */ 00773 int secLevel, /* IN - AuthNoPriv, authPriv etc. */ 00774 u_char * scopedPdu, /* IN */ 00775 /* 00776 * Pointer to scopedPdu will be encrypted by USM if needed 00777 * * and written to packet buffer immediately following 00778 * * securityParameters, entire msg will be authenticated by 00779 * * USM if needed. 00780 */ 00781 size_t scopedPduLen, /* IN - scopedPdu length. */ 00782 void *secStateRef, /* IN */ 00783 /* 00784 * secStateRef, pointer to cached info provided only for 00785 * * Response, otherwise NULL. 00786 */ 00787 u_char * secParams, /* OUT */ 00788 /* 00789 * BER encoded securityParameters pointer to offset within 00790 * * packet buffer where secParams should be written, the 00791 * * entire BER encoded OCTET STRING (including header) is 00792 * * written here by USM secParams = globalData + 00793 * * globalDataLen. 00794 */ 00795 size_t * secParamsLen, /* IN/OUT - Len available, len returned. */ 00796 u_char ** wholeMsg, /* OUT */ 00797 /* 00798 * Complete authenticated/encrypted message - typically 00799 * * the pointer to start of packet buffer provided in 00800 * * globalData is returned here, could also be a separate 00801 * * buffer. 00802 */ 00803 size_t * wholeMsgLen) 00804 { /* IN/OUT - Len available, len returned. */ 00805 size_t otstlen; 00806 size_t seq_len; 00807 size_t msgAuthParmLen; 00808 size_t msgPrivParmLen; 00809 size_t msgSecParmLen; 00810 size_t authParamsOffset; 00811 size_t privParamsOffset; 00812 size_t datalen; 00813 size_t dataOffset; 00814 size_t theTotalLength; 00815 00816 u_char *ptr; 00817 size_t ptr_len; 00818 size_t remaining; 00819 size_t offSet; 00820 u_int boots_uint; 00821 u_int time_uint; 00822 long boots_long; 00823 long time_long; 00824 00825 /* 00826 * Indirection because secStateRef values override parameters. 00827 * 00828 * None of these are to be free'd - they are either pointing to 00829 * what's in the secStateRef or to something either in the 00830 * actual prarmeter list or the user list. 00831 */ 00832 00833 char *theName = NULL; 00834 u_int theNameLength = 0; 00835 u_char *theEngineID = NULL; 00836 u_int theEngineIDLength = 0; 00837 u_char *theAuthKey = NULL; 00838 u_int theAuthKeyLength = 0; 00839 const oid *theAuthProtocol = NULL; 00840 u_int theAuthProtocolLength = 0; 00841 u_char *thePrivKey = NULL; 00842 u_int thePrivKeyLength = 0; 00843 const oid *thePrivProtocol = NULL; 00844 u_int thePrivProtocolLength = 0; 00845 int theSecLevel = 0; /* No defined const for bad 00846 * value (other then err). 00847 */ 00848 00849 DEBUGMSGTL(("usm", "USM processing has begun.\n")); 00850 00851 if (secStateRef != NULL) { 00852 /* 00853 * To hush the compiler for now. XXX 00854 */ 00855 struct usmStateReference *ref 00856 = (struct usmStateReference *) secStateRef; 00857 00858 theName = ref->usr_name; 00859 theNameLength = ref->usr_name_length; 00860 theEngineID = ref->usr_engine_id; 00861 theEngineIDLength = ref->usr_engine_id_length; 00862 00863 if (!theEngineIDLength) { 00864 theEngineID = secEngineID; 00865 theEngineIDLength = secEngineIDLen; 00866 } 00867 00868 theAuthProtocol = ref->usr_auth_protocol; 00869 theAuthProtocolLength = ref->usr_auth_protocol_length; 00870 theAuthKey = ref->usr_auth_key; 00871 theAuthKeyLength = ref->usr_auth_key_length; 00872 thePrivProtocol = ref->usr_priv_protocol; 00873 thePrivProtocolLength = ref->usr_priv_protocol_length; 00874 thePrivKey = ref->usr_priv_key; 00875 thePrivKeyLength = ref->usr_priv_key_length; 00876 theSecLevel = ref->usr_sec_level; 00877 } 00878 00879 /* 00880 * Identify the user record. 00881 */ 00882 else { 00883 struct usmUser *user; 00884 00885 /* 00886 * we do allow an unknown user name for 00887 * unauthenticated requests. 00888 */ 00889 if ((user = usm_get_user(secEngineID, secEngineIDLen, secName)) 00890 == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) { 00891 DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName)); 00892 usm_free_usmStateReference(secStateRef); 00893 return SNMPERR_USM_UNKNOWNSECURITYNAME; 00894 } 00895 00896 theName = secName; 00897 theNameLength = secNameLen; 00898 theEngineID = secEngineID; 00899 theSecLevel = secLevel; 00900 theEngineIDLength = secEngineIDLen; 00901 if (user) { 00902 theAuthProtocol = user->authProtocol; 00903 theAuthProtocolLength = user->authProtocolLen; 00904 theAuthKey = user->authKey; 00905 theAuthKeyLength = user->authKeyLen; 00906 thePrivProtocol = user->privProtocol; 00907 thePrivProtocolLength = user->privProtocolLen; 00908 thePrivKey = user->privKey; 00909 thePrivKeyLength = user->privKeyLen; 00910 } else { 00911 /* 00912 * unknown users can not do authentication (obviously) 00913 */ 00914 theAuthProtocol = usmNoAuthProtocol; 00915 theAuthProtocolLength = 00916 sizeof(usmNoAuthProtocol) / sizeof(oid); 00917 theAuthKey = NULL; 00918 theAuthKeyLength = 0; 00919 thePrivProtocol = usmNoPrivProtocol; 00920 thePrivProtocolLength = 00921 sizeof(usmNoPrivProtocol) / sizeof(oid); 00922 thePrivKey = NULL; 00923 thePrivKeyLength = 0; 00924 } 00925 } /* endif -- secStateRef==NULL */ 00926 00927 00928 /* 00929 * From here to the end of the function, avoid reference to 00930 * secName, secEngineID, secLevel, and associated lengths. 00931 */ 00932 00933 00934 /* 00935 * Check to see if the user can use the requested sec services. 00936 */ 00937 if (usm_check_secLevel_vs_protocols(theSecLevel, 00938 theAuthProtocol, 00939 theAuthProtocolLength, 00940 thePrivProtocol, 00941 thePrivProtocolLength) == 1) { 00942 DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n", 00943 theSecLevel)); 00944 usm_free_usmStateReference(secStateRef); 00945 return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL; 00946 } 00947 00948 00949 /* 00950 * Retrieve the engine information. 00951 * 00952 * XXX No error is declared in the EoP when sending messages to 00953 * unknown engines, processing continues w/ boots/time == (0,0). 00954 */ 00955 if (get_enginetime(theEngineID, theEngineIDLength, 00956 &boots_uint, &time_uint, FALSE) == -1) { 00957 DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data.")); 00958 } 00959 00960 boots_long = boots_uint; 00961 time_long = time_uint; 00962 00963 00964 /* 00965 * Set up the Offsets. 00966 */ 00967 if (usm_calc_offsets(globalDataLen, theSecLevel, theEngineIDLength, 00968 theNameLength, scopedPduLen, boots_long, 00969 time_long, &theTotalLength, &authParamsOffset, 00970 &privParamsOffset, &dataOffset, &datalen, 00971 &msgAuthParmLen, &msgPrivParmLen, &otstlen, 00972 &seq_len, &msgSecParmLen) == -1) { 00973 DEBUGMSGTL(("usm", "Failed calculating offsets.\n")); 00974 usm_free_usmStateReference(secStateRef); 00975 return SNMPERR_USM_GENERICERROR; 00976 } 00977 00978 /* 00979 * So, we have the offsets for the three parts that need to be 00980 * determined, and an overall length. Now we need to make 00981 * sure all of this would fit in the outgoing buffer, and 00982 * whether or not we need to make a new buffer, etc. 00983 */ 00984 00985 00986 /* 00987 * Set wholeMsg as a pointer to globalData. Sanity check for 00988 * the proper size. 00989 * 00990 * Mark workspace in the message with bytes of all 1's to make it 00991 * easier to find mistakes in raw message dumps. 00992 */ 00993 ptr = *wholeMsg = globalData; 00994 if (theTotalLength > *wholeMsgLen) { 00995 DEBUGMSGTL(("usm", "Message won't fit in buffer.\n")); 00996 usm_free_usmStateReference(secStateRef); 00997 return SNMPERR_USM_GENERICERROR; 00998 } 00999 01000 ptr_len = *wholeMsgLen = theTotalLength; 01001 01002 #ifdef NETSNMP_ENABLE_TESTING_CODE 01003 memset(&ptr[globalDataLen], 0xFF, theTotalLength - globalDataLen); 01004 #endif /* NETSNMP_ENABLE_TESTING_CODE */ 01005 01006 /* 01007 * Do the encryption. 01008 */ 01009 if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 01010 size_t encrypted_length = theTotalLength - dataOffset; 01011 size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH); 01012 u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)]; 01013 01014 /* 01015 * XXX Hardwired to seek into a 1DES private key! 01016 */ 01017 #ifdef HAVE_AES 01018 if (ISTRANSFORM(thePrivProtocol, AESPriv)) { 01019 if (!thePrivKey || 01020 usm_set_aes_iv(salt, &salt_length, 01021 htonl(boots_uint), htonl(time_uint), 01022 &ptr[privParamsOffset]) == -1) { 01023 DEBUGMSGTL(("usm", "Can't set AES iv.\n")); 01024 usm_free_usmStateReference(secStateRef); 01025 return SNMPERR_USM_GENERICERROR; 01026 } 01027 } 01028 #endif 01029 #ifndef NETSNMP_DISABLE_DES 01030 if (ISTRANSFORM(thePrivProtocol, DESPriv)) { 01031 if (!thePrivKey || 01032 (usm_set_salt(salt, &salt_length, 01033 thePrivKey + 8, thePrivKeyLength - 8, 01034 &ptr[privParamsOffset]) 01035 == -1)) { 01036 DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n")); 01037 usm_free_usmStateReference(secStateRef); 01038 return SNMPERR_USM_GENERICERROR; 01039 } 01040 } 01041 #endif 01042 01043 if (sc_encrypt(thePrivProtocol, thePrivProtocolLength, 01044 thePrivKey, thePrivKeyLength, 01045 salt, salt_length, 01046 scopedPdu, scopedPduLen, 01047 &ptr[dataOffset], &encrypted_length) 01048 != SNMP_ERR_NOERROR) { 01049 DEBUGMSGTL(("usm", "encryption error.\n")); 01050 usm_free_usmStateReference(secStateRef); 01051 return SNMPERR_USM_ENCRYPTIONERROR; 01052 } 01053 #ifdef NETSNMP_ENABLE_TESTING_CODE 01054 if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { 01055 dump_chunk("usm/dump", "This data was encrypted:", 01056 scopedPdu, scopedPduLen); 01057 dump_chunk("usm/dump", "salt + Encrypted form:", 01058 salt, salt_length); 01059 dump_chunk("usm/dump", NULL, 01060 &ptr[dataOffset], encrypted_length); 01061 dump_chunk("usm/dump", "*wholeMsg:", 01062 *wholeMsg, theTotalLength); 01063 } 01064 #endif 01065 01066 01067 ptr = *wholeMsg; 01068 ptr_len = *wholeMsgLen = theTotalLength; 01069 01070 01071 /* 01072 * XXX Sanity check for salt length should be moved up 01073 * under usm_calc_offsets() or tossed. 01074 */ 01075 if ((encrypted_length != (theTotalLength - dataOffset)) 01076 || (salt_length != msgPrivParmLen)) { 01077 DEBUGMSGTL(("usm", "encryption length error.\n")); 01078 usm_free_usmStateReference(secStateRef); 01079 return SNMPERR_USM_ENCRYPTIONERROR; 01080 } 01081 01082 DEBUGMSGTL(("usm", "Encryption successful.\n")); 01083 } 01084 01085 /* 01086 * No encryption for you! 01087 */ 01088 else { 01089 memcpy(&ptr[dataOffset], scopedPdu, scopedPduLen); 01090 } 01091 01092 01093 01094 /* 01095 * Start filling in the other fields (in prep for authentication). 01096 * 01097 * offSet is an octet string header, which is different from all 01098 * the other headers. 01099 */ 01100 remaining = ptr_len - globalDataLen; 01101 01102 offSet = ptr_len - remaining; 01103 asn_build_header(&ptr[offSet], &remaining, 01104 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | 01105 ASN_OCTET_STR), otstlen); 01106 01107 offSet = ptr_len - remaining; 01108 asn_build_sequence(&ptr[offSet], &remaining, 01109 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len); 01110 01111 offSet = ptr_len - remaining; 01112 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID"); 01113 asn_build_string(&ptr[offSet], &remaining, 01114 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | 01115 ASN_OCTET_STR), theEngineID, 01116 theEngineIDLength); 01117 DEBUGINDENTLESS(); 01118 01119 offSet = ptr_len - remaining; 01120 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots"); 01121 asn_build_int(&ptr[offSet], &remaining, 01122 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), 01123 &boots_long, sizeof(long)); 01124 DEBUGINDENTLESS(); 01125 01126 offSet = ptr_len - remaining; 01127 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime"); 01128 asn_build_int(&ptr[offSet], &remaining, 01129 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), 01130 &time_long, sizeof(long)); 01131 DEBUGINDENTLESS(); 01132 01133 offSet = ptr_len - remaining; 01134 DEBUGDUMPHEADER("send", "msgUserName"); 01135 asn_build_string(&ptr[offSet], &remaining, 01136 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | 01137 ASN_OCTET_STR), (u_char *) theName, 01138 theNameLength); 01139 DEBUGINDENTLESS(); 01140 01141 01142 /* 01143 * Note: if there is no authentication being done, 01144 * msgAuthParmLen is 0, and there is no effect (other than 01145 * inserting a zero-length header) of the following 01146 * statements. 01147 */ 01148 01149 offSet = ptr_len - remaining; 01150 asn_build_header(&ptr[offSet], 01151 &remaining, 01152 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | 01153 ASN_OCTET_STR), msgAuthParmLen); 01154 01155 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV 01156 || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 01157 offSet = ptr_len - remaining; 01158 memset(&ptr[offSet], 0, msgAuthParmLen); 01159 } 01160 01161 remaining -= msgAuthParmLen; 01162 01163 01164 /* 01165 * Note: if there is no encryption being done, msgPrivParmLen 01166 * is 0, and there is no effect (other than inserting a 01167 * zero-length header) of the following statements. 01168 */ 01169 01170 offSet = ptr_len - remaining; 01171 asn_build_header(&ptr[offSet], 01172 &remaining, 01173 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | 01174 ASN_OCTET_STR), msgPrivParmLen); 01175 01176 remaining -= msgPrivParmLen; /* Skipping the IV already there. */ 01177 01178 01179 /* 01180 * For privacy, need to add the octet string header for it. 01181 */ 01182 if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 01183 offSet = ptr_len - remaining; 01184 asn_build_header(&ptr[offSet], 01185 &remaining, 01186 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | 01187 ASN_OCTET_STR), 01188 theTotalLength - dataOffset); 01189 } 01190 01191 01192 /* 01193 * Adjust overall length and store it as the first SEQ length 01194 * of the SNMPv3Message. 01195 * 01196 * FIX 4 is a magic number! 01197 */ 01198 remaining = theTotalLength; 01199 asn_build_sequence(ptr, &remaining, 01200 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 01201 theTotalLength - 4); 01202 01203 01204 /* 01205 * Now, time to consider / do authentication. 01206 */ 01207 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV 01208 || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 01209 size_t temp_sig_len = msgAuthParmLen; 01210 u_char *temp_sig = (u_char *) malloc(temp_sig_len); 01211 01212 if (temp_sig == NULL) { 01213 DEBUGMSGTL(("usm", "Out of memory.\n")); 01214 usm_free_usmStateReference(secStateRef); 01215 return SNMPERR_USM_GENERICERROR; 01216 } 01217 01218 if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength, 01219 theAuthKey, theAuthKeyLength, 01220 ptr, ptr_len, temp_sig, &temp_sig_len) 01221 != SNMP_ERR_NOERROR) { 01222 /* 01223 * FIX temp_sig_len defined?! 01224 */ 01225 SNMP_ZERO(temp_sig, temp_sig_len); 01226 SNMP_FREE(temp_sig); 01227 DEBUGMSGTL(("usm", "Signing failed.\n")); 01228 usm_free_usmStateReference(secStateRef); 01229 return SNMPERR_USM_AUTHENTICATIONFAILURE; 01230 } 01231 01232 if (temp_sig_len != msgAuthParmLen) { 01233 SNMP_ZERO(temp_sig, temp_sig_len); 01234 SNMP_FREE(temp_sig); 01235 DEBUGMSGTL(("usm", "Signing lengths failed.\n")); 01236 usm_free_usmStateReference(secStateRef); 01237 return SNMPERR_USM_AUTHENTICATIONFAILURE; 01238 } 01239 01240 memcpy(&ptr[authParamsOffset], temp_sig, msgAuthParmLen); 01241 01242 SNMP_ZERO(temp_sig, temp_sig_len); 01243 SNMP_FREE(temp_sig); 01244 01245 } 01246 01247 /* 01248 * endif -- create keyed hash 01249 */ 01250 usm_free_usmStateReference(secStateRef); 01251 01252 DEBUGMSGTL(("usm", "USM processing completed.\n")); 01253 01254 return SNMPERR_SUCCESS; 01255 01256 } /* end usm_generate_out_msg() */ 01257 01258 #ifdef NETSNMP_USE_REVERSE_ASNENCODING 01259 int 01260 usm_secmod_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms) 01261 { 01262 if (!parms) 01263 return SNMPERR_GENERR; 01264 01265 return usm_rgenerate_out_msg(parms->msgProcModel, 01266 parms->globalData, parms->globalDataLen, 01267 parms->maxMsgSize, parms->secModel, 01268 parms->secEngineID, parms->secEngineIDLen, 01269 parms->secName, parms->secNameLen, 01270 parms->secLevel, 01271 parms->scopedPdu, parms->scopedPduLen, 01272 parms->secStateRef, 01273 parms->wholeMsg, parms->wholeMsgLen, 01274 parms->wholeMsgOffset); 01275 } 01276 01277 int 01278 usm_rgenerate_out_msg(int msgProcModel, /* (UNUSED) */ 01279 u_char * globalData, /* IN */ 01280 /* 01281 * points at the msgGlobalData, which is of length given by next 01282 * parameter. 01283 */ 01284 size_t globalDataLen, /* IN - Length of msg header data. */ 01285 int maxMsgSize, /* (UNUSED) */ 01286 int secModel, /* (UNUSED) */ 01287 u_char * secEngineID, /* IN - Pointer snmpEngineID. */ 01288 size_t secEngineIDLen, /* IN - SnmpEngineID length. */ 01289 char *secName, /* IN - Pointer to securityName. */ 01290 size_t secNameLen, /* IN - SecurityName length. */ 01291 int secLevel, /* IN - AuthNoPriv, authPriv etc. */ 01292 u_char * scopedPdu, /* IN */ 01293 /* 01294 * Pointer to scopedPdu will be encrypted by USM if needed 01295 * * and written to packet buffer immediately following 01296 * * securityParameters, entire msg will be authenticated by 01297 * * USM if needed. 01298 */ 01299 size_t scopedPduLen, /* IN - scopedPdu length. */ 01300 void *secStateRef, /* IN */ 01301 /* 01302 * secStateRef, pointer to cached info provided only for 01303 * * Response, otherwise NULL. 01304 */ 01305 u_char ** wholeMsg, /* IN/OUT */ 01306 /* 01307 * Points at the pointer to the packet buffer, which might get extended 01308 * if necessary via realloc(). 01309 */ 01310 size_t * wholeMsgLen, /* IN/OUT */ 01311 /* 01312 * Length of the entire packet buffer, **not** the length of the 01313 * packet. 01314 */ 01315 size_t * offset /* IN/OUT */ 01316 /* 01317 * Offset from the end of the packet buffer to the start of the packet, 01318 * also known as the packet length. 01319 */ 01320 ) 01321 { 01322 size_t msgAuthParmLen = 0; 01323 #ifdef NETSNMP_ENABLE_TESTING_CODE 01324 size_t theTotalLength; 01325 #endif 01326 01327 u_int boots_uint; 01328 u_int time_uint; 01329 long boots_long; 01330 long time_long; 01331 01332 /* 01333 * Indirection because secStateRef values override parameters. 01334 * 01335 * None of these are to be free'd - they are either pointing to 01336 * what's in the secStateRef or to something either in the 01337 * actual parameter list or the user list. 01338 */ 01339 01340 char *theName = NULL; 01341 u_int theNameLength = 0; 01342 u_char *theEngineID = NULL; 01343 u_int theEngineIDLength = 0; 01344 u_char *theAuthKey = NULL; 01345 u_int theAuthKeyLength = 0; 01346 const oid *theAuthProtocol = NULL; 01347 u_int theAuthProtocolLength = 0; 01348 u_char *thePrivKey = NULL; 01349 u_int thePrivKeyLength = 0; 01350 const oid *thePrivProtocol = NULL; 01351 u_int thePrivProtocolLength = 0; 01352 int theSecLevel = 0; /* No defined const for bad 01353 * value (other then err). */ 01354 size_t salt_length = 0, save_salt_length = 0, save_salt_offset = 0; 01355 u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)]; 01356 u_char authParams[USM_MAX_AUTHSIZE]; 01357 u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)]; 01358 size_t sp_offset = 0, mac_offset = 0; 01359 int rc = 0; 01360 01361 DEBUGMSGTL(("usm", "USM processing has begun (offset %d)\n", *offset)); 01362 01363 if (secStateRef != NULL) { 01364 /* 01365 * To hush the compiler for now. XXX 01366 */ 01367 struct usmStateReference *ref 01368 = (struct usmStateReference *) secStateRef; 01369 01370 theName = ref->usr_name; 01371 theNameLength = ref->usr_name_length; 01372 theEngineID = ref->usr_engine_id; 01373 theEngineIDLength = ref->usr_engine_id_length; 01374 01375 if (!theEngineIDLength) { 01376 theEngineID = secEngineID; 01377 theEngineIDLength = secEngineIDLen; 01378 } 01379 01380 theAuthProtocol = ref->usr_auth_protocol; 01381 theAuthProtocolLength = ref->usr_auth_protocol_length; 01382 theAuthKey = ref->usr_auth_key; 01383 theAuthKeyLength = ref->usr_auth_key_length; 01384 thePrivProtocol = ref->usr_priv_protocol; 01385 thePrivProtocolLength = ref->usr_priv_protocol_length; 01386 thePrivKey = ref->usr_priv_key; 01387 thePrivKeyLength = ref->usr_priv_key_length; 01388 theSecLevel = ref->usr_sec_level; 01389 } 01390 01391 /* 01392 * * Identify the user record. 01393 */ 01394 else { 01395 struct usmUser *user; 01396 01397 /* 01398 * we do allow an unknown user name for 01399 * unauthenticated requests. 01400 */ 01401 if ((user = usm_get_user(secEngineID, secEngineIDLen, secName)) 01402 == NULL && secLevel != SNMP_SEC_LEVEL_NOAUTH) { 01403 DEBUGMSGTL(("usm", "Unknown User\n")); 01404 usm_free_usmStateReference(secStateRef); 01405 return SNMPERR_USM_UNKNOWNSECURITYNAME; 01406 } 01407 01408 theName = secName; 01409 theNameLength = secNameLen; 01410 theEngineID = secEngineID; 01411 theSecLevel = secLevel; 01412 theEngineIDLength = secEngineIDLen; 01413 if (user) { 01414 theAuthProtocol = user->authProtocol; 01415 theAuthProtocolLength = user->authProtocolLen; 01416 theAuthKey = user->authKey; 01417 theAuthKeyLength = user->authKeyLen; 01418 thePrivProtocol = user->privProtocol; 01419 thePrivProtocolLength = user->privProtocolLen; 01420 thePrivKey = user->privKey; 01421 thePrivKeyLength = user->privKeyLen; 01422 } else { 01423 /* 01424 * unknown users can not do authentication (obviously) 01425 */ 01426 theAuthProtocol = usmNoAuthProtocol; 01427 theAuthProtocolLength = 01428 sizeof(usmNoAuthProtocol) / sizeof(oid); 01429 theAuthKey = NULL; 01430 theAuthKeyLength = 0; 01431 thePrivProtocol = usmNoPrivProtocol; 01432 thePrivProtocolLength = 01433 sizeof(usmNoPrivProtocol) / sizeof(oid); 01434 thePrivKey = NULL; 01435 thePrivKeyLength = 0; 01436 } 01437 } /* endif -- secStateRef==NULL */ 01438 01439 01440 /* 01441 * From here to the end of the function, avoid reference to 01442 * secName, secEngineID, secLevel, and associated lengths. 01443 */ 01444 01445 01446 /* 01447 * Check to see if the user can use the requested sec services. 01448 */ 01449 if (usm_check_secLevel_vs_protocols(theSecLevel, 01450 theAuthProtocol, 01451 theAuthProtocolLength, 01452 thePrivProtocol, 01453 thePrivProtocolLength) == 1) { 01454 DEBUGMSGTL(("usm", "Unsupported Security Level or type (%d)\n", 01455 theSecLevel)); 01456 01457 usm_free_usmStateReference(secStateRef); 01458 return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL; 01459 } 01460 01461 01462 /* 01463 * * Retrieve the engine information. 01464 * * 01465 * * XXX No error is declared in the EoP when sending messages to 01466 * * unknown engines, processing continues w/ boots/time == (0,0). 01467 */ 01468 if (get_enginetime(theEngineID, theEngineIDLength, 01469 &boots_uint, &time_uint, FALSE) == -1) { 01470 DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data.")); 01471 } 01472 01473 boots_long = boots_uint; 01474 time_long = time_uint; 01475 01476 if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 01477 /* 01478 * Initially assume that the ciphertext will end up the same size as 01479 * the plaintext plus some padding. Really sc_encrypt ought to be able 01480 * to grow this for us, a la asn_realloc_rbuild_<type> functions, but 01481 * this will do for now. 01482 */ 01483 u_char *ciphertext = NULL; 01484 size_t ciphertextlen = scopedPduLen + 64; 01485 01486 if ((ciphertext = (u_char *) malloc(ciphertextlen)) == NULL) { 01487 DEBUGMSGTL(("usm", 01488 "couldn't malloc %d bytes for encrypted PDU\n", 01489 ciphertextlen)); 01490 usm_free_usmStateReference(secStateRef); 01491 return SNMPERR_MALLOC; 01492 } 01493 01494 /* 01495 * XXX Hardwired to seek into a 1DES private key! 01496 */ 01497 #ifdef HAVE_AES 01498 if (ISTRANSFORM(thePrivProtocol, AESPriv)) { 01499 salt_length = BYTESIZE(USM_AES_SALT_LENGTH); 01500 save_salt_length = BYTESIZE(USM_AES_SALT_LENGTH)/2; 01501 save_salt_offset = 0; 01502 if (!thePrivKey || 01503 usm_set_aes_iv(salt, &salt_length, 01504 htonl(boots_uint), htonl(time_uint), 01505 iv) == -1) { 01506 DEBUGMSGTL(("usm", "Can't set AES iv.\n")); 01507 usm_free_usmStateReference(secStateRef); 01508 SNMP_FREE(ciphertext); 01509 return SNMPERR_USM_GENERICERROR; 01510 } 01511 } 01512 #endif 01513 #ifndef NETSNMP_DISABLE_DES 01514 if (ISTRANSFORM(thePrivProtocol, DESPriv)) { 01515 salt_length = BYTESIZE(USM_DES_SALT_LENGTH); 01516 save_salt_length = BYTESIZE(USM_DES_SALT_LENGTH); 01517 save_salt_offset = 0; 01518 if (!thePrivKey || (usm_set_salt(salt, &salt_length, 01519 thePrivKey + 8, 01520 thePrivKeyLength - 8, 01521 iv) == -1)) { 01522 DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n")); 01523 usm_free_usmStateReference(secStateRef); 01524 SNMP_FREE(ciphertext); 01525 return SNMPERR_USM_GENERICERROR; 01526 } 01527 } 01528 #endif 01529 #ifdef NETSNMP_ENABLE_TESTING_CODE 01530 if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { 01531 dump_chunk("usm/dump", "This data was encrypted:", 01532 scopedPdu, scopedPduLen); 01533 } 01534 #endif 01535 01536 if (sc_encrypt(thePrivProtocol, thePrivProtocolLength, 01537 thePrivKey, thePrivKeyLength, 01538 salt, salt_length, 01539 scopedPdu, scopedPduLen, 01540 ciphertext, &ciphertextlen) != SNMP_ERR_NOERROR) { 01541 DEBUGMSGTL(("usm", "encryption error.\n")); 01542 usm_free_usmStateReference(secStateRef); 01543 SNMP_FREE(ciphertext); 01544 return SNMPERR_USM_ENCRYPTIONERROR; 01545 } 01546 01547 /* 01548 * Write the encrypted scopedPdu back into the packet buffer. 01549 */ 01550 01551 #ifdef NETSNMP_ENABLE_TESTING_CODE 01552 theTotalLength = *wholeMsgLen; 01553 #endif 01554 *offset = 0; 01555 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, 01556 (u_char) (ASN_UNIVERSAL | 01557 ASN_PRIMITIVE | 01558 ASN_OCTET_STR), 01559 ciphertext, ciphertextlen); 01560 #ifdef NETSNMP_ENABLE_TESTING_CODE 01561 if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { 01562 dump_chunk("usm/dump", "salt + Encrypted form: ", salt, 01563 salt_length); 01564 dump_chunk("usm/dump", "wholeMsg:", 01565 (*wholeMsg + *wholeMsgLen - *offset), *offset); 01566 } 01567 #endif 01568 01569 DEBUGMSGTL(("usm", "Encryption successful.\n")); 01570 SNMP_FREE(ciphertext); 01571 } else { 01572 /* 01573 * theSecLevel != SNMP_SEC_LEVEL_AUTHPRIV 01574 */ 01575 } 01576 01577 /* 01578 * Start encoding the msgSecurityParameters. 01579 */ 01580 01581 sp_offset = *offset; 01582 01583 DEBUGDUMPHEADER("send", "msgPrivacyParameters"); 01584 /* 01585 * msgPrivacyParameters (warning: assumes DES salt). 01586 */ 01587 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, 01588 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE 01589 | ASN_OCTET_STR), 01590 iv, 01591 save_salt_length); 01592 DEBUGINDENTLESS(); 01593 if (rc == 0) { 01594 DEBUGMSGTL(("usm", "building privParams failed.\n")); 01595 usm_free_usmStateReference(secStateRef); 01596 return SNMPERR_TOO_LONG; 01597 } 01598 01599 DEBUGDUMPHEADER("send", "msgAuthenticationParameters"); 01600 /* 01601 * msgAuthenticationParameters (warnings assumes 0x00 by 12). 01602 */ 01603 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV 01604 || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 01605 memset(authParams, 0, USM_MD5_AND_SHA_AUTH_LEN); 01606 msgAuthParmLen = USM_MD5_AND_SHA_AUTH_LEN; 01607 } 01608 01609 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, 01610 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE 01611 | ASN_OCTET_STR), authParams, 01612 msgAuthParmLen); 01613 DEBUGINDENTLESS(); 01614 if (rc == 0) { 01615 DEBUGMSGTL(("usm", "building authParams failed.\n")); 01616 usm_free_usmStateReference(secStateRef); 01617 return SNMPERR_TOO_LONG; 01618 } 01619 01620 /* 01621 * Remember where to put the actual HMAC we calculate later on. An 01622 * encoded OCTET STRING of length USM_MD5_AND_SHA_AUTH_LEN has an ASN.1 01623 * header of length 2, hence the fudge factor. 01624 */ 01625 01626 mac_offset = *offset - 2; 01627 01628 /* 01629 * msgUserName. 01630 */ 01631 DEBUGDUMPHEADER("send", "msgUserName"); 01632 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, 01633 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE 01634 | ASN_OCTET_STR), 01635 (u_char *) theName, theNameLength); 01636 DEBUGINDENTLESS(); 01637 if (rc == 0) { 01638 DEBUGMSGTL(("usm", "building authParams failed.\n")); 01639 usm_free_usmStateReference(secStateRef); 01640 return SNMPERR_TOO_LONG; 01641 } 01642 01643 /* 01644 * msgAuthoritativeEngineTime. 01645 */ 01646 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime"); 01647 rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1, 01648 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | 01649 ASN_INTEGER), &time_long, 01650 sizeof(long)); 01651 DEBUGINDENTLESS(); 01652 if (rc == 0) { 01653 DEBUGMSGTL(("usm", 01654 "building msgAuthoritativeEngineTime failed.\n")); 01655 usm_free_usmStateReference(secStateRef); 01656 return SNMPERR_TOO_LONG; 01657 } 01658 01659 /* 01660 * msgAuthoritativeEngineBoots. 01661 */ 01662 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots"); 01663 rc = asn_realloc_rbuild_int(wholeMsg, wholeMsgLen, offset, 1, 01664 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | 01665 ASN_INTEGER), &boots_long, 01666 sizeof(long)); 01667 DEBUGINDENTLESS(); 01668 if (rc == 0) { 01669 DEBUGMSGTL(("usm", 01670 "building msgAuthoritativeEngineBoots failed.\n")); 01671 usm_free_usmStateReference(secStateRef); 01672 return SNMPERR_TOO_LONG; 01673 } 01674 01675 DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID"); 01676 rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1, 01677 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE 01678 | ASN_OCTET_STR), theEngineID, 01679 theEngineIDLength); 01680 DEBUGINDENTLESS(); 01681 if (rc == 0) { 01682 DEBUGMSGTL(("usm", "building msgAuthoritativeEngineID failed.\n")); 01683 usm_free_usmStateReference(secStateRef); 01684 return SNMPERR_TOO_LONG; 01685 } 01686 01687 /* 01688 * USM msgSecurityParameters sequence header 01689 */ 01690 rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1, 01691 (u_char) (ASN_SEQUENCE | 01692 ASN_CONSTRUCTOR), 01693 *offset - sp_offset); 01694 if (rc == 0) { 01695 DEBUGMSGTL(("usm", "building usm security parameters failed.\n")); 01696 usm_free_usmStateReference(secStateRef); 01697 return SNMPERR_TOO_LONG; 01698 } 01699 01700 /* 01701 * msgSecurityParameters OCTET STRING wrapper. 01702 */ 01703 rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1, 01704 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE 01705 | ASN_OCTET_STR), 01706 *offset - sp_offset); 01707 01708 if (rc == 0) { 01709 DEBUGMSGTL(("usm", "building msgSecurityParameters failed.\n")); 01710 usm_free_usmStateReference(secStateRef); 01711 return SNMPERR_TOO_LONG; 01712 } 01713 01714 /* 01715 * Copy in the msgGlobalData and msgVersion. 01716 */ 01717 while ((*wholeMsgLen - *offset) < globalDataLen) { 01718 if (!asn_realloc(wholeMsg, wholeMsgLen)) { 01719 DEBUGMSGTL(("usm", "building global data failed.\n")); 01720 usm_free_usmStateReference(secStateRef); 01721 return SNMPERR_TOO_LONG; 01722 } 01723 } 01724 01725 *offset += globalDataLen; 01726 memcpy(*wholeMsg + *wholeMsgLen - *offset, globalData, globalDataLen); 01727 01728 /* 01729 * Total packet sequence. 01730 */ 01731 rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1, 01732 (u_char) (ASN_SEQUENCE | 01733 ASN_CONSTRUCTOR), *offset); 01734 if (rc == 0) { 01735 DEBUGMSGTL(("usm", "building master packet sequence failed.\n")); 01736 usm_free_usmStateReference(secStateRef); 01737 return SNMPERR_TOO_LONG; 01738 } 01739 01740 /* 01741 * Now consider / do authentication. 01742 */ 01743 01744 if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || 01745 theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 01746 size_t temp_sig_len = msgAuthParmLen; 01747 u_char *temp_sig = (u_char *) malloc(temp_sig_len); 01748 u_char *proto_msg = *wholeMsg + *wholeMsgLen - *offset; 01749 size_t proto_msg_len = *offset; 01750 01751 01752 if (temp_sig == NULL) { 01753 DEBUGMSGTL(("usm", "Out of memory.\n")); 01754 usm_free_usmStateReference(secStateRef); 01755 return SNMPERR_USM_GENERICERROR; 01756 } 01757 01758 if (sc_generate_keyed_hash(theAuthProtocol, theAuthProtocolLength, 01759 theAuthKey, theAuthKeyLength, 01760 proto_msg, proto_msg_len, 01761 temp_sig, &temp_sig_len) 01762 != SNMP_ERR_NOERROR) { 01763 SNMP_FREE(temp_sig); 01764 DEBUGMSGTL(("usm", "Signing failed.\n")); 01765 usm_free_usmStateReference(secStateRef); 01766 return SNMPERR_USM_AUTHENTICATIONFAILURE; 01767 } 01768 01769 if (temp_sig_len != msgAuthParmLen) { 01770 SNMP_FREE(temp_sig); 01771 DEBUGMSGTL(("usm", "Signing lengths failed.\n")); 01772 usm_free_usmStateReference(secStateRef); 01773 return SNMPERR_USM_AUTHENTICATIONFAILURE; 01774 } 01775 01776 memcpy(*wholeMsg + *wholeMsgLen - mac_offset, temp_sig, 01777 msgAuthParmLen); 01778 SNMP_FREE(temp_sig); 01779 } 01780 /* 01781 * endif -- create keyed hash 01782 */ 01783 usm_free_usmStateReference(secStateRef); 01784 DEBUGMSGTL(("usm", "USM processing completed.\n")); 01785 return SNMPERR_SUCCESS; 01786 } /* end usm_rgenerate_out_msg() */ 01787 01788 #endif /* */ 01789 01790 01791 01792 /*******************************************************************-o-****** 01793 * usm_parse_security_parameters 01794 * 01795 * Parameters: 01796 * (See list below...) 01797 * 01798 * Returns: 01799 * 0 On success, 01800 * -1 Otherwise. 01801 * 01802 * tab stop 4 01803 * 01804 * Extracts values from the security header and data portions of the 01805 * incoming buffer. 01806 */ 01807 int 01808 usm_parse_security_parameters(u_char * secParams, 01809 size_t remaining, 01810 u_char * secEngineID, 01811 size_t * secEngineIDLen, 01812 u_int * boots_uint, 01813 u_int * time_uint, 01814 char *secName, 01815 size_t * secNameLen, 01816 u_char * signature, 01817 size_t * signature_length, 01818 u_char * salt, 01819 size_t * salt_length, u_char ** data_ptr) 01820 { 01821 u_char *parse_ptr = secParams; 01822 u_char *value_ptr; 01823 u_char *next_ptr; 01824 u_char type_value; 01825 01826 size_t octet_string_length = remaining; 01827 size_t sequence_length; 01828 size_t remaining_bytes; 01829 01830 long boots_long; 01831 long time_long; 01832 01833 u_int origNameLen; 01834 01835 01836 /* 01837 * Eat the first octet header. 01838 */ 01839 if ((value_ptr = asn_parse_sequence(parse_ptr, &octet_string_length, 01840 &type_value, 01841 (ASN_UNIVERSAL | ASN_PRIMITIVE | 01842 ASN_OCTET_STR), 01843 "usm first octet")) == NULL) { 01844 /* 01845 * RETURN parse error 01846 */ return -1; 01847 } 01848 01849 01850 /* 01851 * Eat the sequence header. 01852 */ 01853 parse_ptr = value_ptr; 01854 sequence_length = octet_string_length; 01855 01856 if ((value_ptr = asn_parse_sequence(parse_ptr, &sequence_length, 01857 &type_value, 01858 (ASN_SEQUENCE | ASN_CONSTRUCTOR), 01859 "usm sequence")) == NULL) { 01860 /* 01861 * RETURN parse error 01862 */ return -1; 01863 } 01864 01865 01866 /* 01867 * Retrieve the engineID. 01868 */ 01869 parse_ptr = value_ptr; 01870 remaining_bytes = sequence_length; 01871 01872 DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineID"); 01873 if ((next_ptr 01874 = asn_parse_string(parse_ptr, &remaining_bytes, &type_value, 01875 secEngineID, secEngineIDLen)) == NULL) { 01876 DEBUGINDENTLESS(); 01877 /* 01878 * RETURN parse error 01879 */ return -1; 01880 } 01881 DEBUGINDENTLESS(); 01882 01883 if (type_value != 01884 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) { 01885 /* 01886 * RETURN parse error 01887 */ return -1; 01888 } 01889 01890 01891 /* 01892 * Retrieve the engine boots, notice switch in the way next_ptr and 01893 * remaining_bytes are used (to accomodate the asn code). 01894 */ 01895 DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineBoots"); 01896 if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value, 01897 &boots_long, sizeof(long))) == NULL) { 01898 DEBUGINDENTLESS(); 01899 /* 01900 * RETURN parse error 01901 */ return -1; 01902 } 01903 DEBUGINDENTLESS(); 01904 01905 if (type_value != 01906 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) { 01907 DEBUGINDENTLESS(); 01908 /* 01909 * RETURN parse error 01910 */ return -1; 01911 } 01912 01913 *boots_uint = (u_int) boots_long; 01914 01915 01916 /* 01917 * Retrieve the time value. 01918 */ 01919 DEBUGDUMPHEADER("recv", "msgAuthoritativeEngineTime"); 01920 if ((next_ptr = asn_parse_int(next_ptr, &remaining_bytes, &type_value, 01921 &time_long, sizeof(long))) == NULL) { 01922 /* 01923 * RETURN parse error 01924 */ return -1; 01925 } 01926 DEBUGINDENTLESS(); 01927 01928 if (type_value != 01929 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER)) { 01930 /* 01931 * RETURN parse error 01932 */ return -1; 01933 } 01934 01935 *time_uint = (u_int) time_long; 01936 01937 if (*boots_uint > ENGINEBOOT_MAX || *time_uint > ENGINETIME_MAX) { 01938 return -1; 01939 } 01940 01941 /* 01942 * Retrieve the secName. 01943 */ 01944 origNameLen = *secNameLen; 01945 01946 01947 DEBUGDUMPHEADER("recv", "msgUserName"); 01948 if ((next_ptr 01949 = asn_parse_string(next_ptr, &remaining_bytes, &type_value, 01950 (u_char *) secName, secNameLen)) == NULL) { 01951 DEBUGINDENTLESS(); 01952 /* 01953 * RETURN parse error 01954 */ return -1; 01955 } 01956 DEBUGINDENTLESS(); 01957 01958 /* 01959 * FIX -- doesn't this also indicate a buffer overrun? 01960 */ 01961 if ((int) origNameLen < *secNameLen + 1) { 01962 /* 01963 * RETURN parse error, but it's really a parameter error 01964 */ 01965 return -1; 01966 } 01967 01968 if (*secNameLen > 32) { 01969 /* 01970 * This is a USM-specific limitation over and above the above 01971 * limitation (which will probably default to the length of an 01972 * SnmpAdminString, i.e. 255). See RFC 2574, sec. 2.4. 01973 */ 01974 return -1; 01975 } 01976 01977 secName[*secNameLen] = '\0'; 01978 01979 if (type_value != 01980 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) { 01981 /* 01982 * RETURN parse error 01983 */ return -1; 01984 } 01985 01986 01987 /* 01988 * Retrieve the signature and blank it if there. 01989 */ 01990 DEBUGDUMPHEADER("recv", "msgAuthenticationParameters"); 01991 if ((next_ptr 01992 = asn_parse_string(next_ptr, &remaining_bytes, &type_value, 01993 signature, signature_length)) == NULL) { 01994 DEBUGINDENTLESS(); 01995 /* 01996 * RETURN parse error 01997 */ return -1; 01998 } 01999 DEBUGINDENTLESS(); 02000 02001 if (type_value != 02002 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) { 02003 /* 02004 * RETURN parse error 02005 */ return -1; 02006 } 02007 02008 if (*signature_length != 0) { /* Blanking for authentication step later */ 02009 memset(next_ptr - (u_long) * signature_length, 02010 0, *signature_length); 02011 } 02012 02013 02014 /* 02015 * Retrieve the salt. 02016 * 02017 * Note that the next ptr is where the data section starts. 02018 */ 02019 DEBUGDUMPHEADER("recv", "msgPrivacyParameters"); 02020 if ((*data_ptr 02021 = asn_parse_string(next_ptr, &remaining_bytes, &type_value, 02022 salt, salt_length)) == NULL) { 02023 DEBUGINDENTLESS(); 02024 /* 02025 * RETURN parse error 02026 */ return -2; 02027 } 02028 DEBUGINDENTLESS(); 02029 02030 if (type_value != 02031 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR)) { 02032 /* 02033 * RETURN parse error 02034 */ return -2; 02035 } 02036 02037 return 0; 02038 02039 } /* end usm_parse_security_parameters() */ 02040 02041 02042 02043 02044 /*******************************************************************-o-****** 02045 * usm_check_and_update_timeliness 02046 * 02047 * Parameters: 02048 * *secEngineID 02049 * secEngineIDen 02050 * boots_uint 02051 * time_uint 02052 * *error 02053 * 02054 * Returns: 02055 * 0 On success, 02056 * -1 Otherwise. 02057 * 02058 * 02059 * Performs the incoming timeliness checking and setting. 02060 */ 02061 int 02062 usm_check_and_update_timeliness(u_char * secEngineID, 02063 size_t secEngineIDLen, 02064 u_int boots_uint, 02065 u_int time_uint, int *error) 02066 { 02067 u_char myID[USM_MAX_ID_LENGTH]; 02068 u_long myIDLength = 02069 snmpv3_get_engineID(myID, USM_MAX_ID_LENGTH); 02070 u_int myBoots; 02071 u_int myTime; 02072 02073 02074 02075 if ((myIDLength > USM_MAX_ID_LENGTH) || (myIDLength == 0)) { 02076 /* 02077 * We're probably already screwed...buffer overwrite. XXX? 02078 */ 02079 DEBUGMSGTL(("usm", "Buffer overflow.\n")); 02080 *error = SNMPERR_USM_GENERICERROR; 02081 return -1; 02082 } 02083 02084 myBoots = snmpv3_local_snmpEngineBoots(); 02085 myTime = snmpv3_local_snmpEngineTime(); 02086 02087 02088 /* 02089 * IF the time involved is local 02090 * Make sure message is inside the time window 02091 * ELSE 02092 * IF boots is higher or boots is the same and time is higher 02093 * remember this new data 02094 * ELSE 02095 * IF !(boots same and time within USM_TIME_WINDOW secs) 02096 * Message is too old 02097 * ELSE 02098 * Message is ok, but don't take time 02099 * ENDIF 02100 * ENDIF 02101 * ENDIF 02102 */ 02103 02104 /* 02105 * This is a local reference. 02106 */ 02107 if ((int) secEngineIDLen == myIDLength 02108 && memcmp(secEngineID, myID, myIDLength) == 0) { 02109 u_int time_difference = myTime > time_uint ? 02110 myTime - time_uint : time_uint - myTime; 02111 02112 if (boots_uint == ENGINEBOOT_MAX 02113 || boots_uint != myBoots 02114 || time_difference > USM_TIME_WINDOW) { 02115 if (snmp_increment_statistic(STAT_USMSTATSNOTINTIMEWINDOWS) == 02116 0) { 02117 DEBUGMSGTL(("usm", "%s\n", 02118 "Failed to increment statistic.")); 02119 } 02120 02121 DEBUGMSGTL(("usm", 02122 "boot_uint %u myBoots %u time_diff %u => not in time window\n", 02123 boots_uint, myBoots, time_difference)); 02124 *error = SNMPERR_USM_NOTINTIMEWINDOW; 02125 return -1; 02126 } 02127 02128 *error = SNMPERR_SUCCESS; 02129 return 0; 02130 } 02131 02132 /* 02133 * This is a remote reference. 02134 */ 02135 else { 02136 u_int theirBoots, theirTime, theirLastTime; 02137 u_int time_difference; 02138 02139 if (get_enginetime_ex(secEngineID, secEngineIDLen, 02140 &theirBoots, &theirTime, 02141 &theirLastTime, TRUE) 02142 != SNMPERR_SUCCESS) { 02143 DEBUGMSGTL(("usm", "%s\n", 02144 "Failed to get remote engine's times.")); 02145 02146 *error = SNMPERR_USM_GENERICERROR; 02147 return -1; 02148 } 02149 02150 time_difference = theirTime > time_uint ? 02151 theirTime - time_uint : time_uint - theirTime; 02152 02153 02154 /* 02155 * XXX Contrary to the pseudocode: 02156 * See if boots is invalid first. 02157 */ 02158 if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint) { 02159 DEBUGMSGTL(("usm", "%s\n", "Remote boot count invalid.")); 02160 02161 *error = SNMPERR_USM_NOTINTIMEWINDOW; 02162 return -1; 02163 } 02164 02165 02166 /* 02167 * Boots is ok, see if the boots is the same but the time 02168 * is old. 02169 */ 02170 if (theirBoots == boots_uint && time_uint < theirLastTime) { 02171 if (time_difference > USM_TIME_WINDOW) { 02172 DEBUGMSGTL(("usm", "%s\n", "Message too old.")); 02173 *error = SNMPERR_USM_NOTINTIMEWINDOW; 02174 return -1; 02175 } 02176 02177 else { /* Old, but acceptable */ 02178 02179 *error = SNMPERR_SUCCESS; 02180 return 0; 02181 } 02182 } 02183 02184 02185 /* 02186 * Message is ok, either boots has been advanced, or 02187 * time is greater than before with the same boots. 02188 */ 02189 02190 if (set_enginetime(secEngineID, secEngineIDLen, 02191 boots_uint, time_uint, TRUE) 02192 != SNMPERR_SUCCESS) { 02193 DEBUGMSGTL(("usm", "%s\n", 02194 "Failed updating remote boot/time.")); 02195 *error = SNMPERR_USM_GENERICERROR; 02196 return -1; 02197 } 02198 02199 *error = SNMPERR_SUCCESS; 02200 return 0; /* Fresh message and time updated */ 02201 02202 } /* endif -- local or remote time reference. */ 02203 02204 02205 } /* end usm_check_and_update_timeliness() */ 02206 02207 02208 02209 int 02210 usm_secmod_process_in_msg(struct snmp_secmod_incoming_params *parms) 02211 { 02212 if (!parms) 02213 return SNMPERR_GENERR; 02214 02215 return usm_process_in_msg(parms->msgProcModel, 02216 parms->maxMsgSize, 02217 parms->secParams, 02218 parms->secModel, 02219 parms->secLevel, 02220 parms->wholeMsg, 02221 parms->wholeMsgLen, 02222 parms->secEngineID, 02223 parms->secEngineIDLen, 02224 parms->secName, 02225 parms->secNameLen, 02226 parms->scopedPdu, 02227 parms->scopedPduLen, 02228 parms->maxSizeResponse, 02229 parms->secStateRef, 02230 parms->sess, parms->msg_flags); 02231 } 02232 02233 /*******************************************************************-o-****** 02234 * usm_process_in_msg 02235 * 02236 * Parameters: 02237 * (See list below...) 02238 * 02239 * Returns: 02240 * SNMPERR_SUCCESS On success. 02241 * SNMPERR_USM_AUTHENTICATIONFAILURE 02242 * SNMPERR_USM_DECRYPTIONERROR 02243 * SNMPERR_USM_GENERICERROR 02244 * SNMPERR_USM_PARSEERROR 02245 * SNMPERR_USM_UNKNOWNENGINEID 02246 * SNMPERR_USM_PARSEERROR 02247 * SNMPERR_USM_UNKNOWNSECURITYNAME 02248 * SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL 02249 * 02250 * 02251 * ASSUMES size of decrypt_buf will always be >= size of encrypted sPDU. 02252 * 02253 * FIX Memory leaks if secStateRef is allocated and a return occurs 02254 * without cleaning up. May contain secrets... 02255 */ 02256 int 02257 usm_process_in_msg(int msgProcModel, /* (UNUSED) */ 02258 size_t maxMsgSize, /* IN - Used to calc maxSizeResponse. */ 02259 u_char * secParams, /* IN - BER encoded securityParameters. */ 02260 int secModel, /* (UNUSED) */ 02261 int secLevel, /* IN - AuthNoPriv, authPriv etc. */ 02262 u_char * wholeMsg, /* IN - Original v3 message. */ 02263 size_t wholeMsgLen, /* IN - Msg length. */ 02264 u_char * secEngineID, /* OUT - Pointer snmpEngineID. */ 02265 size_t * secEngineIDLen, /* IN/OUT - Len available, len returned. */ 02266 /* 02267 * NOTE: Memory provided by caller. 02268 */ 02269 char *secName, /* OUT - Pointer to securityName. */ 02270 size_t * secNameLen, /* IN/OUT - Len available, len returned. */ 02271 u_char ** scopedPdu, /* OUT - Pointer to plaintext scopedPdu. */ 02272 size_t * scopedPduLen, /* IN/OUT - Len available, len returned. */ 02273 size_t * maxSizeResponse, /* OUT - Max size of Response PDU. */ 02274 void **secStateRf, /* OUT - Ref to security state. */ 02275 netsnmp_session * sess, /* IN - session which got the message */ 02276 u_char msg_flags) 02277 { /* IN - v3 Message flags. */ 02278 size_t remaining = wholeMsgLen - (u_int) 02279 ((u_long) * secParams - (u_long) * wholeMsg); 02280 u_int boots_uint; 02281 u_int time_uint; 02282 #ifdef HAVE_AES 02283 u_int net_boots, net_time; 02284 #endif 02285 u_char signature[BYTESIZE(USM_MAX_KEYEDHASH_LENGTH)]; 02286 size_t signature_length = BYTESIZE(USM_MAX_KEYEDHASH_LENGTH); 02287 u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)]; 02288 size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH); 02289 u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)]; 02290 u_int iv_length = BYTESIZE(USM_MAX_SALT_LENGTH); 02291 u_char *data_ptr; 02292 u_char *value_ptr; 02293 u_char type_value; 02294 u_char *end_of_overhead = NULL; 02295 int error; 02296 int i, rc = 0; 02297 struct usmStateReference **secStateRef = 02298 (struct usmStateReference **) secStateRf; 02299 02300 struct usmUser *user; 02301 02302 02303 DEBUGMSGTL(("usm", "USM processing begun...\n")); 02304 02305 02306 if (secStateRef) { 02307 usm_free_usmStateReference(*secStateRef); 02308 *secStateRef = usm_malloc_usmStateReference(); 02309 if (*secStateRef == NULL) { 02310 DEBUGMSGTL(("usm", "Out of memory.\n")); 02311 return SNMPERR_USM_GENERICERROR; 02312 } 02313 } 02314 02315 02316 /* 02317 * Make sure the *secParms is an OCTET STRING. 02318 * Extract the user name, engine ID, and security level. 02319 */ 02320 if ((rc = usm_parse_security_parameters(secParams, remaining, 02321 secEngineID, secEngineIDLen, 02322 &boots_uint, &time_uint, 02323 secName, secNameLen, 02324 signature, &signature_length, 02325 salt, &salt_length, 02326 &data_ptr)) < 0) { 02327 DEBUGMSGTL(("usm", "Parsing failed (rc %d).\n", rc)); 02328 if (rc == -2) { 02329 /* 02330 * This indicates a decryptionError. 02331 */ 02332 if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) == 02333 0) { 02334 DEBUGMSGTL(("usm", "%s\n", 02335 "Failed to increment statistic.")); 02336 } 02337 return SNMPERR_USM_DECRYPTIONERROR; 02338 } 02339 if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) { 02340 DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic.")); 02341 } 02342 return SNMPERR_USM_PARSEERROR; 02343 } 02344 02345 /* 02346 * RFC 2574 section 8.3.2 02347 * 1) If the privParameters field is not an 8-octet OCTET STRING, 02348 * then an error indication (decryptionError) is returned to the 02349 * calling module. 02350 */ 02351 if ((secLevel == SNMP_SEC_LEVEL_AUTHPRIV) && (salt_length != 8)) { 02352 if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) == 02353 0) { 02354 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic.")); 02355 } 02356 return SNMPERR_USM_DECRYPTIONERROR; 02357 } 02358 02359 if (secLevel != SNMP_SEC_LEVEL_AUTHPRIV) { 02360 /* 02361 * pull these out now so reports can use them 02362 */ 02363 *scopedPdu = data_ptr; 02364 *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg); 02365 end_of_overhead = data_ptr; 02366 } 02367 02368 if (secStateRef) { 02369 /* 02370 * Cache the name, engine ID, and security level, 02371 * * per step 2 (section 3.2) 02372 */ 02373 if (usm_set_usmStateReference_name 02374 (*secStateRef, secName, *secNameLen) == -1) { 02375 DEBUGMSGTL(("usm", "%s\n", "Couldn't cache name.")); 02376 return SNMPERR_USM_GENERICERROR; 02377 } 02378 02379 if (usm_set_usmStateReference_engine_id 02380 (*secStateRef, secEngineID, *secEngineIDLen) == -1) { 02381 DEBUGMSGTL(("usm", "%s\n", "Couldn't cache engine id.")); 02382 return SNMPERR_USM_GENERICERROR; 02383 } 02384 02385 if (usm_set_usmStateReference_sec_level(*secStateRef, secLevel) == 02386 -1) { 02387 DEBUGMSGTL(("usm", "%s\n", "Couldn't cache security level.")); 02388 return SNMPERR_USM_GENERICERROR; 02389 } 02390 } 02391 02392 02393 /* 02394 * Locate the engine ID record. 02395 * If it is unknown, then either create one or note this as an error. 02396 */ 02397 if ((sess && (sess->isAuthoritative == SNMP_SESS_AUTHORITATIVE || 02398 (sess->isAuthoritative == SNMP_SESS_UNKNOWNAUTH && 02399 (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)))) || 02400 (!sess && (msg_flags & SNMP_MSG_FLAG_RPRT_BIT))) { 02401 if (ISENGINEKNOWN(secEngineID, *secEngineIDLen) == FALSE) { 02402 DEBUGMSGTL(("usm", "Unknown Engine ID.\n")); 02403 if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNENGINEIDS) == 02404 0) { 02405 DEBUGMSGTL(("usm", "%s\n", 02406 "Failed to increment statistic.")); 02407 } 02408 return SNMPERR_USM_UNKNOWNENGINEID; 02409 } 02410 } else { 02411 if (ENSURE_ENGINE_RECORD(secEngineID, *secEngineIDLen) 02412 != SNMPERR_SUCCESS) { 02413 DEBUGMSGTL(("usm", "%s\n", "Couldn't ensure engine record.")); 02414 return SNMPERR_USM_GENERICERROR; 02415 } 02416 02417 } 02418 02419 02420 /* 02421 * Locate the User record. 02422 * If the user/engine ID is unknown, report this as an error. 02423 */ 02424 if ((user = usm_get_user_from_list(secEngineID, *secEngineIDLen, 02425 secName, userList, 02426 (((sess && sess->isAuthoritative == 02427 SNMP_SESS_AUTHORITATIVE) || 02428 (!sess)) ? 0 : 1))) 02429 == NULL) { 02430 DEBUGMSGTL(("usm", "Unknown User(%s)\n", secName)); 02431 if (snmp_increment_statistic(STAT_USMSTATSUNKNOWNUSERNAMES) == 0) { 02432 DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic.")); 02433 } 02434 return SNMPERR_USM_UNKNOWNSECURITYNAME; 02435 } 02436 02437 02438 /* 02439 * Make sure the security level is appropriate. 02440 */ 02441 if (usm_check_secLevel(secLevel, user) == 1) { 02442 DEBUGMSGTL(("usm", "Unsupported Security Level (%d).\n", 02443 secLevel)); 02444 if (snmp_increment_statistic 02445 (STAT_USMSTATSUNSUPPORTEDSECLEVELS) == 0) { 02446 DEBUGMSGTL(("usm", "%s\n", "Failed to increment statistic.")); 02447 } 02448 return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL; 02449 } 02450 02451 02452 /* 02453 * Check the authentication credentials of the message. 02454 */ 02455 if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV 02456 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 02457 if (sc_check_keyed_hash(user->authProtocol, user->authProtocolLen, 02458 user->authKey, user->authKeyLen, 02459 wholeMsg, wholeMsgLen, 02460 signature, signature_length) 02461 != SNMP_ERR_NOERROR) { 02462 DEBUGMSGTL(("usm", "Verification failed.\n")); 02463 if (snmp_increment_statistic(STAT_USMSTATSWRONGDIGESTS) == 0) { 02464 DEBUGMSGTL(("usm", "%s\n", 02465 "Failed to increment statistic.")); 02466 } 02467 snmp_log(LOG_WARNING, "Authentication failed for %s\n", 02468 user->name); 02469 return SNMPERR_USM_AUTHENTICATIONFAILURE; 02470 } 02471 02472 DEBUGMSGTL(("usm", "Verification succeeded.\n")); 02473 } 02474 02475 02476 /* 02477 * Steps 10-11 user is already set - relocated before timeliness 02478 * check in case it fails - still save user data for response. 02479 * 02480 * Cache the keys and protocol oids, per step 11 (s3.2). 02481 */ 02482 if (secStateRef) { 02483 if (usm_set_usmStateReference_auth_protocol(*secStateRef, 02484 user->authProtocol, 02485 user-> 02486 authProtocolLen) == 02487 -1) { 02488 DEBUGMSGTL(("usm", "%s\n", 02489 "Couldn't cache authentication protocol.")); 02490 return SNMPERR_USM_GENERICERROR; 02491 } 02492 02493 if (usm_set_usmStateReference_auth_key(*secStateRef, 02494 user->authKey, 02495 user->authKeyLen) == -1) { 02496 DEBUGMSGTL(("usm", "%s\n", 02497 "Couldn't cache authentication key.")); 02498 return SNMPERR_USM_GENERICERROR; 02499 } 02500 02501 if (usm_set_usmStateReference_priv_protocol(*secStateRef, 02502 user->privProtocol, 02503 user-> 02504 privProtocolLen) == 02505 -1) { 02506 DEBUGMSGTL(("usm", "%s\n", 02507 "Couldn't cache privacy protocol.")); 02508 return SNMPERR_USM_GENERICERROR; 02509 } 02510 02511 if (usm_set_usmStateReference_priv_key(*secStateRef, 02512 user->privKey, 02513 user->privKeyLen) == -1) { 02514 DEBUGMSGTL(("usm", "%s\n", "Couldn't cache privacy key.")); 02515 return SNMPERR_USM_GENERICERROR; 02516 } 02517 } 02518 02519 02520 /* 02521 * Perform the timeliness/time manager functions. 02522 */ 02523 if (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV 02524 || secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 02525 if (usm_check_and_update_timeliness(secEngineID, *secEngineIDLen, 02526 boots_uint, time_uint, 02527 &error) == -1) { 02528 return error; 02529 } 02530 } 02531 #ifdef LCD_TIME_SYNC_OPT 02532 /* 02533 * Cache the unauthenticated time to use in case we don't have 02534 * anything better - this guess will be no worse than (0,0) 02535 * that we normally use. 02536 */ 02537 else { 02538 set_enginetime(secEngineID, *secEngineIDLen, 02539 boots_uint, time_uint, FALSE); 02540 } 02541 #endif /* LCD_TIME_SYNC_OPT */ 02542 02543 02544 /* 02545 * If needed, decrypt the scoped PDU. 02546 */ 02547 if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { 02548 remaining = wholeMsgLen - (data_ptr - wholeMsg); 02549 02550 if ((value_ptr = asn_parse_sequence(data_ptr, &remaining, 02551 &type_value, 02552 (ASN_UNIVERSAL | ASN_PRIMITIVE 02553 | ASN_OCTET_STR), 02554 "encrypted sPDU")) == NULL) { 02555 DEBUGMSGTL(("usm", "%s\n", 02556 "Failed while parsing encrypted sPDU.")); 02557 if (snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0) { 02558 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic.")); 02559 } 02560 usm_free_usmStateReference(*secStateRef); 02561 *secStateRef = NULL; 02562 return SNMPERR_USM_PARSEERROR; 02563 } 02564 02565 #ifndef NETSNMP_DISABLE_DES 02566 if (ISTRANSFORM(user->privProtocol, DESPriv)) { 02567 /* 02568 * From RFC2574: 02569 * 02570 * "Before decryption, the encrypted data length is verified. 02571 * If the length of the OCTET STRING to be decrypted is not 02572 * an integral multiple of 8 octets, the decryption process 02573 * is halted and an appropriate exception noted." 02574 */ 02575 02576 if (remaining % 8 != 0) { 02577 DEBUGMSGTL(("usm", 02578 "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %d)\n", 02579 remaining, remaining % 8)); 02580 if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) == 02581 0) { 02582 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic.")); 02583 } 02584 usm_free_usmStateReference(*secStateRef); 02585 *secStateRef = NULL; 02586 return SNMPERR_USM_DECRYPTIONERROR; 02587 } 02588 02589 end_of_overhead = value_ptr; 02590 02591 /* 02592 * XOR the salt with the last (iv_length) bytes 02593 * of the priv_key to obtain the IV. 02594 */ 02595 iv_length = BYTESIZE(USM_DES_SALT_LENGTH); 02596 for (i = 0; i < (int) iv_length; i++) 02597 iv[i] = salt[i] ^ user->privKey[iv_length + i]; 02598 } 02599 #endif 02600 #ifdef HAVE_AES 02601 if (ISTRANSFORM(user->privProtocol, AESPriv)) { 02602 iv_length = BYTESIZE(USM_AES_SALT_LENGTH); 02603 net_boots = ntohl(boots_uint); 02604 net_time = ntohl(time_uint); 02605 memcpy(iv, &net_boots, 4); 02606 memcpy(iv+4, &net_time, 4); 02607 memcpy(iv+8, salt, salt_length); 02608 } 02609 #endif 02610 02611 if (sc_decrypt(user->privProtocol, user->privProtocolLen, 02612 user->privKey, user->privKeyLen, 02613 iv, iv_length, 02614 value_ptr, remaining, *scopedPdu, scopedPduLen) 02615 != SNMP_ERR_NOERROR) { 02616 DEBUGMSGTL(("usm", "%s\n", "Failed decryption.")); 02617 if (snmp_increment_statistic 02618 (STAT_USMSTATSDECRYPTIONERRORS) == 0) { 02619 DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic.")); 02620 } 02621 return SNMPERR_USM_DECRYPTIONERROR; 02622 } 02623 #ifdef NETSNMP_ENABLE_TESTING_CODE 02624 if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { 02625 dump_chunk("usm/dump", "Cypher Text", value_ptr, remaining); 02626 dump_chunk("usm/dump", "salt + Encrypted form:", 02627 salt, salt_length); 02628 dump_chunk("usm/dump", "IV + Encrypted form:", iv, iv_length); 02629 dump_chunk("usm/dump", "Decrypted chunk:", 02630 *scopedPdu, *scopedPduLen); 02631 } 02632 #endif 02633 } 02634 /* 02635 * sPDU is plaintext. 02636 */ 02637 else { 02638 *scopedPdu = data_ptr; 02639 *scopedPduLen = wholeMsgLen - (data_ptr - wholeMsg); 02640 end_of_overhead = data_ptr; 02641 02642 } /* endif -- PDU decryption */ 02643 02644 02645 /* 02646 * Calculate the biggest sPDU for the response (i.e., whole - ovrhd). 02647 * 02648 * FIX Correct? 02649 */ 02650 *maxSizeResponse = maxMsgSize - (int) 02651 ((u_long) end_of_overhead - (u_long) wholeMsg); 02652 02653 02654 DEBUGMSGTL(("usm", "USM processing completed.\n")); 02655 02656 return SNMPERR_SUCCESS; 02657 02658 } /* end usm_process_in_msg() */ 02659 02660 void 02661 usm_handle_report(void *sessp, 02662 netsnmp_transport *transport, netsnmp_session *session, 02663 int result, netsnmp_pdu *pdu) 02664 { 02665 /* 02666 * handle reportable errors 02667 */ 02668 02669 /* this will get in our way */ 02670 usm_free_usmStateReference(pdu->securityStateRef); 02671 pdu->securityStateRef = NULL; 02672 02673 switch (result) { 02674 case SNMPERR_USM_AUTHENTICATIONFAILURE: 02675 { 02676 int res = session->s_snmp_errno; 02677 session->s_snmp_errno = result; 02678 if (session->callback) { 02679 session->callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE, 02680 session, pdu->reqid, pdu, 02681 session->callback_magic); 02682 } 02683 session->s_snmp_errno = res; 02684 } 02685 case SNMPERR_USM_UNKNOWNENGINEID: 02686 case SNMPERR_USM_UNKNOWNSECURITYNAME: 02687 case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL: 02688 case SNMPERR_USM_NOTINTIMEWINDOW: 02689 case SNMPERR_USM_DECRYPTIONERROR: 02690 02691 if (SNMP_CMD_CONFIRMED(pdu->command) || 02692 (pdu->command == 0 02693 && (pdu->flags & SNMP_MSG_FLAG_RPRT_BIT))) { 02694 netsnmp_pdu *pdu2; 02695 int flags = pdu->flags; 02696 02697 pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY; 02698 pdu2 = snmp_clone_pdu(pdu); 02699 pdu->flags = pdu2->flags = flags; 02700 snmpv3_make_report(pdu2, result); 02701 if (0 == snmp_sess_send(sessp, pdu2)) { 02702 snmp_free_pdu(pdu2); 02703 /* 02704 * TODO: indicate error 02705 */ 02706 } 02707 } 02708 break; 02709 } 02710 } 02711 void 02712 init_usm(void) 02713 { 02714 struct snmp_secmod_def *def; 02715 02716 DEBUGMSGTL(("init_usm", "unit_usm: %d %d\n", usmNoPrivProtocol[0], 02717 usmNoPrivProtocol[1])); 02718 02719 sc_init(); /* initalize scapi code */ 02720 02721 /* 02722 * register ourselves as a security service 02723 */ 02724 def = SNMP_MALLOC_STRUCT(snmp_secmod_def); 02725 /* 02726 * XXX: def->init_sess_secmod move stuff from snmp_api.c 02727 */ 02728 def->encode_reverse = usm_secmod_rgenerate_out_msg; 02729 def->encode_forward = usm_secmod_generate_out_msg; 02730 def->decode = usm_secmod_process_in_msg; 02731 def->pdu_free_state_ref = usm_free_usmStateReference; 02732 def->handle_report = usm_handle_report; 02733 register_sec_mod(USM_SEC_MODEL_NUMBER, "usm", def); 02734 02735 snmp_register_callback(SNMP_CALLBACK_LIBRARY, 02736 SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, 02737 init_usm_post_config, NULL); 02738 02739 snmp_register_callback(SNMP_CALLBACK_LIBRARY, 02740 SNMP_CALLBACK_SHUTDOWN, 02741 deinit_usm_post_config, NULL); 02742 02743 snmp_register_callback(SNMP_CALLBACK_LIBRARY, 02744 SNMP_CALLBACK_SHUTDOWN, 02745 free_engineID, NULL); 02746 02747 } 02748 02749 void 02750 init_usm_conf(const char *app) 02751 { 02752 register_config_handler(app, "usmUser", 02753 usm_parse_config_usmUser, NULL, NULL); 02754 register_config_handler(app, "createUser", 02755 usm_parse_create_usmUser, NULL, 02756 "username (MD5|SHA) passphrase [DES [passphrase]]"); 02757 02758 /* 02759 * we need to be called back later 02760 */ 02761 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, 02762 usm_store_users, NULL); 02763 } 02764 02765 /* 02766 * initializations for the USM. 02767 * 02768 * Should be called after the (engineid) configuration files have been read. 02769 * 02770 * Set "arbitrary" portion of salt to a random number. 02771 */ 02772 int 02773 init_usm_post_config(int majorid, int minorid, void *serverarg, 02774 void *clientarg) 02775 { 02776 size_t salt_integer_len = sizeof(salt_integer); 02777 02778 if (sc_random((u_char *) & salt_integer, &salt_integer_len) != 02779 SNMPERR_SUCCESS) { 02780 DEBUGMSGTL(("usm", "sc_random() failed: using time() as salt.\n")); 02781 salt_integer = (u_int) time(NULL); 02782 } 02783 02784 #ifdef HAVE_AES 02785 salt_integer_len = sizeof (salt_integer64_1); 02786 if (sc_random((u_char *) & salt_integer64_1, &salt_integer_len) != 02787 SNMPERR_SUCCESS) { 02788 DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes1 salt.\n")); 02789 salt_integer64_1 = (u_int) time(NULL); 02790 } 02791 salt_integer_len = sizeof (salt_integer64_1); 02792 if (sc_random((u_char *) & salt_integer64_2, &salt_integer_len) != 02793 SNMPERR_SUCCESS) { 02794 DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes2 salt.\n")); 02795 salt_integer64_2 = (u_int) time(NULL); 02796 } 02797 #endif 02798 02799 #ifndef NETSNMP_DISABLE_MD5 02800 noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol, 02801 USM_LENGTH_OID_TRANSFORM, 02802 #ifndef NETSNMP_DISABLE_DES 02803 usmDESPrivProtocol, 02804 #else 02805 usmAESPrivProtocol, 02806 #endif 02807 USM_LENGTH_OID_TRANSFORM); 02808 #else 02809 noNameUser = usm_create_initial_user("", usmHMACSHA1AuthProtocol, 02810 USM_LENGTH_OID_TRANSFORM, 02811 #ifndef NETSNMP_DISABLE_DES 02812 usmDESPrivProtocol, 02813 #else 02814 usmAESPrivProtocol, 02815 #endif 02816 USM_LENGTH_OID_TRANSFORM); 02817 #endif 02818 02819 if ( noNameUser ) { 02820 SNMP_FREE(noNameUser->engineID); 02821 noNameUser->engineIDLen = 0; 02822 } 02823 02824 return SNMPERR_SUCCESS; 02825 } /* end init_usm_post_config() */ 02826 02827 int 02828 deinit_usm_post_config(int majorid, int minorid, void *serverarg, 02829 void *clientarg) 02830 { 02831 if (usm_free_user(noNameUser) != NULL) { 02832 DEBUGMSGTL(("deinit_usm_post_config", "could not free initial user\n")); 02833 return SNMPERR_GENERR; 02834 } 02835 noNameUser = NULL; 02836 02837 DEBUGMSGTL(("deinit_usm_post_config", "initial user removed\n")); 02838 return SNMPERR_SUCCESS; 02839 } /* end deinit_usm_post_config() */ 02840 02841 void 02842 clear_user_list(void) 02843 { 02844 struct usmUser *tmp = userList, *next = NULL; 02845 02846 while (tmp != NULL) { 02847 next = tmp->next; 02848 usm_free_user(tmp); 02849 tmp = next; 02850 } 02851 userList = NULL; 02852 02853 } 02854 02855 /*******************************************************************-o-****** 02856 * usm_check_secLevel 02857 * 02858 * Parameters: 02859 * level 02860 * *user 02861 * 02862 * Returns: 02863 * 0 On success, 02864 * -1 Otherwise. 02865 * 02866 * Checks that a given security level is valid for a given user. 02867 */ 02868 int 02869 usm_check_secLevel(int level, struct usmUser *user) 02870 { 02871 02872 if (user->userStatus != RS_ACTIVE) 02873 return -1; 02874 02875 DEBUGMSGTL(("comparex", "Comparing: %d %d ", usmNoPrivProtocol[0], 02876 usmNoPrivProtocol[1])); 02877 DEBUGMSGOID(("comparex", usmNoPrivProtocol, 02878 sizeof(usmNoPrivProtocol) / sizeof(oid))); 02879 DEBUGMSG(("comparex", "\n")); 02880 if (level == SNMP_SEC_LEVEL_AUTHPRIV 02881 && (netsnmp_oid_equals(user->privProtocol, user->privProtocolLen, 02882 usmNoPrivProtocol, 02883 sizeof(usmNoPrivProtocol) / sizeof(oid)) == 02884 0)) { 02885 DEBUGMSGTL(("usm", "Level: %d\n", level)); 02886 DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name)); 02887 DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen)); 02888 DEBUGMSG(("usm", ", User Priv Protocol: ")); 02889 DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen)); 02890 DEBUGMSG(("usm", "\n")); 02891 return 1; 02892 } 02893 if ((level == SNMP_SEC_LEVEL_AUTHPRIV 02894 || level == SNMP_SEC_LEVEL_AUTHNOPRIV) 02895 && 02896 (netsnmp_oid_equals 02897 (user->authProtocol, user->authProtocolLen, usmNoAuthProtocol, 02898 sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) { 02899 DEBUGMSGTL(("usm", "Level: %d\n", level)); 02900 DEBUGMSGTL(("usm", "User (%s) Auth Protocol: ", user->name)); 02901 DEBUGMSGOID(("usm", user->authProtocol, user->authProtocolLen)); 02902 DEBUGMSG(("usm", ", User Priv Protocol: ")); 02903 DEBUGMSGOID(("usm", user->privProtocol, user->privProtocolLen)); 02904 DEBUGMSG(("usm", "\n")); 02905 return 1; 02906 } 02907 02908 return 0; 02909 02910 } /* end usm_check_secLevel() */ 02911 02912 02913 02914 02915 /*******************************************************************-o-****** 02916 * usm_check_secLevel_vs_protocols 02917 * 02918 * Parameters: 02919 * level 02920 * *authProtocol 02921 * authProtocolLen 02922 * *privProtocol 02923 * privProtocolLen 02924 * 02925 * Returns: 02926 * 0 On success, 02927 * 1 Otherwise. 02928 * 02929 * Same as above but with explicitly named transform types instead of taking 02930 * from the usmUser structure. 02931 */ 02932 int 02933 usm_check_secLevel_vs_protocols(int level, 02934 const oid * authProtocol, 02935 u_int authProtocolLen, 02936 const oid * privProtocol, 02937 u_int privProtocolLen) 02938 { 02939 02940 if (level == SNMP_SEC_LEVEL_AUTHPRIV 02941 && 02942 (netsnmp_oid_equals 02943 (privProtocol, privProtocolLen, usmNoPrivProtocol, 02944 sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0)) { 02945 DEBUGMSGTL(("usm", "Level: %d\n", level)); 02946 DEBUGMSGTL(("usm", "Auth Protocol: ")); 02947 DEBUGMSGOID(("usm", authProtocol, authProtocolLen)); 02948 DEBUGMSG(("usm", ", Priv Protocol: ")); 02949 DEBUGMSGOID(("usm", privProtocol, privProtocolLen)); 02950 DEBUGMSG(("usm", "\n")); 02951 return 1; 02952 } 02953 if ((level == SNMP_SEC_LEVEL_AUTHPRIV 02954 || level == SNMP_SEC_LEVEL_AUTHNOPRIV) 02955 && 02956 (netsnmp_oid_equals 02957 (authProtocol, authProtocolLen, usmNoAuthProtocol, 02958 sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0)) { 02959 DEBUGMSGTL(("usm", "Level: %d\n", level)); 02960 DEBUGMSGTL(("usm", "Auth Protocol: ")); 02961 DEBUGMSGOID(("usm", authProtocol, authProtocolLen)); 02962 DEBUGMSG(("usm", ", Priv Protocol: ")); 02963 DEBUGMSGOID(("usm", privProtocol, privProtocolLen)); 02964 DEBUGMSG(("usm", "\n")); 02965 return 1; 02966 } 02967 02968 return 0; 02969 02970 } /* end usm_check_secLevel_vs_protocols() */ 02971 02972 02973 02974 02975 /* 02976 * usm_get_user(): Returns a user from userList based on the engineID, 02977 * engineIDLen and name of the requested user. 02978 */ 02979 02980 struct usmUser * 02981 usm_get_user(u_char * engineID, size_t engineIDLen, char *name) 02982 { 02983 DEBUGMSGTL(("usm", "getting user %s\n", name)); 02984 return usm_get_user_from_list(engineID, engineIDLen, name, userList, 02985 1); 02986 } 02987 02988 struct usmUser * 02989 usm_get_user_from_list(u_char * engineID, size_t engineIDLen, 02990 char *name, struct usmUser *puserList, 02991 int use_default) 02992 { 02993 struct usmUser *ptr; 02994 char noName[] = ""; 02995 if (name == NULL) 02996 name = noName; 02997 for (ptr = puserList; ptr != NULL; ptr = ptr->next) { 02998 if (ptr->name && !strcmp(ptr->name, name)) { 02999 DEBUGMSGTL(("usm", "match on user %s\n", ptr->name)); 03000 if (ptr->engineIDLen == engineIDLen && 03001 ((ptr->engineID == NULL && engineID == NULL) || 03002 (ptr->engineID != NULL && engineID != NULL && 03003 memcmp(ptr->engineID, engineID, engineIDLen) == 0))) 03004 return ptr; 03005 DEBUGMSGTL(("usm", "no match on engineID (")); 03006 DEBUGMSGHEX(("usm", engineID, engineIDLen)); 03007 DEBUGMSG(("usm", ")\n")); 03008 } 03009 } 03010 03011 /* 03012 * return "" user used to facilitate engineID discovery 03013 */ 03014 if (use_default && !strcmp(name, "")) 03015 return noNameUser; 03016 return NULL; 03017 } 03018 03019 /* 03020 * usm_add_user(): Add's a user to the userList, sorted by the 03021 * engineIDLength then the engineID then the name length then the name 03022 * to facilitate getNext calls on a usmUser table which is indexed by 03023 * these values. 03024 * 03025 * Note: userList must not be NULL (obviously), as thats a rather trivial 03026 * addition and is left to the API user. 03027 * 03028 * returns the head of the list (which could change due to this add). 03029 */ 03030 03031 struct usmUser * 03032 usm_add_user(struct usmUser *user) 03033 { 03034 struct usmUser *uptr; 03035 uptr = usm_add_user_to_list(user, userList); 03036 if (uptr != NULL) 03037 userList = uptr; 03038 return uptr; 03039 } 03040 03041 struct usmUser * 03042 usm_add_user_to_list(struct usmUser *user, struct usmUser *puserList) 03043 { 03044 struct usmUser *nptr, *pptr, *optr; 03045 03046 /* 03047 * loop through puserList till we find the proper, sorted place to 03048 * insert the new user 03049 */ 03050 /* XXX - how to handle a NULL user->name ?? */ 03051 /* XXX - similarly for a NULL nptr->name ?? */ 03052 for (nptr = puserList, pptr = NULL; nptr != NULL; 03053 pptr = nptr, nptr = nptr->next) { 03054 if (nptr->engineIDLen > user->engineIDLen) 03055 break; 03056 03057 if (user->engineID == NULL && nptr->engineID != NULL) 03058 break; 03059 03060 if (nptr->engineIDLen == user->engineIDLen && 03061 (nptr->engineID != NULL && user->engineID != NULL && 03062 memcmp(nptr->engineID, user->engineID, 03063 user->engineIDLen) > 0)) 03064 break; 03065 03066 if (!(nptr->engineID == NULL && user->engineID != NULL)) { 03067 if (nptr->engineIDLen == user->engineIDLen && 03068 ((nptr->engineID == NULL && user->engineID == NULL) || 03069 memcmp(nptr->engineID, user->engineID, 03070 user->engineIDLen) == 0) 03071 && strlen(nptr->name) > strlen(user->name)) 03072 break; 03073 03074 if (nptr->engineIDLen == user->engineIDLen && 03075 ((nptr->engineID == NULL && user->engineID == NULL) || 03076 memcmp(nptr->engineID, user->engineID, 03077 user->engineIDLen) == 0) 03078 && strlen(nptr->name) == strlen(user->name) 03079 && strcmp(nptr->name, user->name) > 0) 03080 break; 03081 03082 if (nptr->engineIDLen == user->engineIDLen && 03083 ((nptr->engineID == NULL && user->engineID == NULL) || 03084 memcmp(nptr->engineID, user->engineID, 03085 user->engineIDLen) == 0) 03086 && strlen(nptr->name) == strlen(user->name) 03087 && strcmp(nptr->name, user->name) == 0) { 03088 /* 03089 * the user is an exact match of a previous entry. 03090 * Credentials may be different, though, so remove 03091 * the old entry (and add the new one)! 03092 */ 03093 if (pptr) { /* change prev's next pointer */ 03094 pptr->next = nptr->next; 03095 } 03096 if (nptr->next) { /* change next's prev pointer */ 03097 nptr->next->prev = pptr; 03098 } 03099 optr = nptr; 03100 nptr = optr->next; /* add new user at this position */ 03101 /* free the old user */ 03102 optr->next=NULL; 03103 optr->prev=NULL; 03104 usm_free_user(optr); 03105 break; /* new user will be added below */ 03106 } 03107 } 03108 } 03109 03110 /* 03111 * nptr should now point to the user that we need to add ourselves 03112 * in front of, and pptr should be our new 'prev'. 03113 */ 03114 03115 /* 03116 * change our pointers 03117 */ 03118 user->prev = pptr; 03119 user->next = nptr; 03120 03121 /* 03122 * change the next's prev pointer 03123 */ 03124 if (user->next) 03125 user->next->prev = user; 03126 03127 /* 03128 * change the prev's next pointer 03129 */ 03130 if (user->prev) 03131 user->prev->next = user; 03132 03133 /* 03134 * rewind to the head of the list and return it (since the new head 03135 * could be us, we need to notify the above routine who the head now is. 03136 */ 03137 for (pptr = user; pptr->prev != NULL; pptr = pptr->prev); 03138 return pptr; 03139 } 03140 03141 /* 03142 * usm_remove_user(): finds and removes a user from a list 03143 */ 03144 struct usmUser * 03145 usm_remove_user(struct usmUser *user) 03146 { 03147 return usm_remove_user_from_list(user, &userList); 03148 } 03149 03150 struct usmUser * 03151 usm_remove_user_from_list(struct usmUser *user, 03152 struct usmUser **ppuserList) 03153 { 03154 struct usmUser *nptr, *pptr; 03155 03156 /* 03157 * NULL pointers aren't allowed 03158 */ 03159 if (ppuserList == NULL) 03160 return NULL; 03161 03162 if (*ppuserList == NULL) 03163 return NULL; 03164 03165 /* 03166 * find the user in the list 03167 */ 03168 for (nptr = *ppuserList, pptr = NULL; nptr != NULL; 03169 pptr = nptr, nptr = nptr->next) { 03170 if (nptr == user) 03171 break; 03172 } 03173 03174 if (nptr) { 03175 /* 03176 * remove the user from the linked list 03177 */ 03178 if (pptr) { 03179 pptr->next = nptr->next; 03180 } 03181 if (nptr->next) { 03182 nptr->next->prev = pptr; 03183 } 03184 } else { 03185 /* 03186 * user didn't exist 03187 */ 03188 return NULL; 03189 } 03190 if (nptr == *ppuserList) /* we're the head of the list, need to change 03191 * * the head to the next user */ 03192 *ppuserList = nptr->next; 03193 return *ppuserList; 03194 } /* end usm_remove_user_from_list() */ 03195 03196 03197 03198 03199 /* 03200 * usm_free_user(): calls free() on all needed parts of struct usmUser and 03201 * the user himself. 03202 * 03203 * Note: This should *not* be called on an object in a list (IE, 03204 * remove it from the list first, and set next and prev to NULL), but 03205 * will try to reconnect the list pieces again if it is called this 03206 * way. If called on the head of the list, the entire list will be 03207 * lost. 03208 */ 03209 struct usmUser * 03210 usm_free_user(struct usmUser *user) 03211 { 03212 if (user == NULL) 03213 return NULL; 03214 03215 SNMP_FREE(user->engineID); 03216 SNMP_FREE(user->name); 03217 SNMP_FREE(user->secName); 03218 SNMP_FREE(user->cloneFrom); 03219 SNMP_FREE(user->userPublicString); 03220 SNMP_FREE(user->authProtocol); 03221 SNMP_FREE(user->privProtocol); 03222 03223 if (user->authKey != NULL) { 03224 SNMP_ZERO(user->authKey, user->authKeyLen); 03225 SNMP_FREE(user->authKey); 03226 } 03227 03228 if (user->privKey != NULL) { 03229 SNMP_ZERO(user->privKey, user->privKeyLen); 03230 SNMP_FREE(user->privKey); 03231 } 03232 03233 03234 /* 03235 * FIX Why not put this check *first?* 03236 */ 03237 if (user->prev != NULL) { /* ack, this shouldn't happen */ 03238 user->prev->next = user->next; 03239 } 03240 if (user->next != NULL) { 03241 user->next->prev = user->prev; 03242 if (user->prev != NULL) /* ack this is really bad, because it means 03243 * * we'll loose the head of some structure tree */ 03244 DEBUGMSGTL(("usm", 03245 "Severe: Asked to free the head of a usmUser tree somewhere.")); 03246 } 03247 03248 03249 SNMP_ZERO(user, sizeof(*user)); 03250 SNMP_FREE(user); 03251 03252 return NULL; /* for convenience to returns from calling functions */ 03253 03254 } /* end usm_free_user() */ 03255 03256 03257 03258 03259 /* 03260 * take a given user and clone the security info into another 03261 */ 03262 struct usmUser * 03263 usm_cloneFrom_user(struct usmUser *from, struct usmUser *to) 03264 { 03265 /* 03266 * copy the authProtocol oid row pointer 03267 */ 03268 SNMP_FREE(to->authProtocol); 03269 03270 if ((to->authProtocol = 03271 snmp_duplicate_objid(from->authProtocol, 03272 from->authProtocolLen)) != NULL) 03273 to->authProtocolLen = from->authProtocolLen; 03274 else 03275 to->authProtocolLen = 0; 03276 03277 03278 /* 03279 * copy the authKey 03280 */ 03281 SNMP_FREE(to->authKey); 03282 03283 if (from->authKeyLen > 0 && 03284 (to->authKey = (u_char *) malloc(from->authKeyLen)) 03285 != NULL) { 03286 to->authKeyLen = from->authKeyLen; 03287 memcpy(to->authKey, from->authKey, to->authKeyLen); 03288 } else { 03289 to->authKey = NULL; 03290 to->authKeyLen = 0; 03291 } 03292 03293 03294 /* 03295 * copy the privProtocol oid row pointer 03296 */ 03297 SNMP_FREE(to->privProtocol); 03298 03299 if ((to->privProtocol = 03300 snmp_duplicate_objid(from->privProtocol, 03301 from->privProtocolLen)) != NULL) 03302 to->privProtocolLen = from->privProtocolLen; 03303 else 03304 to->privProtocolLen = 0; 03305 03306 /* 03307 * copy the privKey 03308 */ 03309 SNMP_FREE(to->privKey); 03310 03311 if (from->privKeyLen > 0 && 03312 (to->privKey = (u_char *) malloc(from->privKeyLen)) 03313 != NULL) { 03314 to->privKeyLen = from->privKeyLen; 03315 memcpy(to->privKey, from->privKey, to->privKeyLen); 03316 } else { 03317 to->privKey = NULL; 03318 to->privKeyLen = 0; 03319 } 03320 return to; 03321 } 03322 03323 /* 03324 * usm_create_user(void): 03325 * create a default empty user, instantiating only the auth/priv 03326 * protocols to noAuth and noPriv OID pointers 03327 */ 03328 struct usmUser * 03329 usm_create_user(void) 03330 { 03331 struct usmUser *newUser; 03332 03333 /* 03334 * create the new user 03335 */ 03336 newUser = (struct usmUser *) calloc(1, sizeof(struct usmUser)); 03337 if (newUser == NULL) 03338 return NULL; 03339 03340 /* 03341 * fill the auth/priv protocols 03342 */ 03343 if ((newUser->authProtocol = 03344 snmp_duplicate_objid(usmNoAuthProtocol, 03345 sizeof(usmNoAuthProtocol) / sizeof(oid))) == 03346 NULL) 03347 return usm_free_user(newUser); 03348 newUser->authProtocolLen = sizeof(usmNoAuthProtocol) / sizeof(oid); 03349 03350 if ((newUser->privProtocol = 03351 snmp_duplicate_objid(usmNoPrivProtocol, 03352 sizeof(usmNoPrivProtocol) / sizeof(oid))) == 03353 NULL) 03354 return usm_free_user(newUser); 03355 newUser->privProtocolLen = sizeof(usmNoPrivProtocol) / sizeof(oid); 03356 03357 /* 03358 * set the storage type to nonvolatile, and the status to ACTIVE 03359 */ 03360 newUser->userStorageType = ST_NONVOLATILE; 03361 newUser->userStatus = RS_ACTIVE; 03362 return newUser; 03363 03364 } /* end usm_clone_user() */ 03365 03366 03367 03368 03369 /* 03370 * usm_create_initial_user(void): 03371 * creates an initial user, filled with the defaults defined in the 03372 * USM document. 03373 */ 03374 struct usmUser * 03375 usm_create_initial_user(const char *name, 03376 const oid * authProtocol, size_t authProtocolLen, 03377 const oid * privProtocol, size_t privProtocolLen) 03378 { 03379 struct usmUser *newUser = usm_create_user(); 03380 if (newUser == NULL) 03381 return NULL; 03382 03383 if ((newUser->name = strdup(name)) == NULL) 03384 return usm_free_user(newUser); 03385 03386 if ((newUser->secName = strdup(name)) == NULL) 03387 return usm_free_user(newUser); 03388 03389 if ((newUser->engineID = 03390 snmpv3_generate_engineID(&newUser->engineIDLen)) == NULL) 03391 return usm_free_user(newUser); 03392 03393 if ((newUser->cloneFrom = (oid *) malloc(sizeof(oid) * 2)) == NULL) 03394 return usm_free_user(newUser); 03395 newUser->cloneFrom[0] = 0; 03396 newUser->cloneFrom[1] = 0; 03397 newUser->cloneFromLen = 2; 03398 03399 SNMP_FREE(newUser->privProtocol); 03400 if ((newUser->privProtocol = snmp_duplicate_objid(privProtocol, 03401 privProtocolLen)) == 03402 NULL) { 03403 return usm_free_user(newUser); 03404 } 03405 newUser->privProtocolLen = privProtocolLen; 03406 03407 SNMP_FREE(newUser->authProtocol); 03408 if ((newUser->authProtocol = snmp_duplicate_objid(authProtocol, 03409 authProtocolLen)) == 03410 NULL) { 03411 return usm_free_user(newUser); 03412 } 03413 newUser->authProtocolLen = authProtocolLen; 03414 03415 newUser->userStatus = RS_ACTIVE; 03416 newUser->userStorageType = ST_READONLY; 03417 03418 return newUser; 03419 } 03420 03421 /* 03422 * this is a callback that can store all known users based on a 03423 * previously registered application ID 03424 */ 03425 int 03426 usm_store_users(int majorID, int minorID, void *serverarg, void *clientarg) 03427 { 03428 /* 03429 * figure out our application name 03430 */ 03431 char *appname = (char *) clientarg; 03432 if (appname == NULL) { 03433 appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 03434 NETSNMP_DS_LIB_APPTYPE); 03435 } 03436 03437 /* 03438 * save the user base 03439 */ 03440 usm_save_users("usmUser", appname); 03441 03442 /* 03443 * never fails 03444 */ 03445 return SNMPERR_SUCCESS; 03446 } 03447 03448 03449 /* 03450 * usm_save_users(): saves a list of users to the persistent cache 03451 */ 03452 void 03453 usm_save_users(const char *token, const char *type) 03454 { 03455 usm_save_users_from_list(userList, token, type); 03456 } 03457 03458 void 03459 usm_save_users_from_list(struct usmUser *puserList, const char *token, 03460 const char *type) 03461 { 03462 struct usmUser *uptr; 03463 for (uptr = puserList; uptr != NULL; uptr = uptr->next) { 03464 if (uptr->userStorageType == ST_NONVOLATILE) 03465 usm_save_user(uptr, token, type); 03466 } 03467 } 03468 03469 /* 03470 * usm_save_user(): saves a user to the persistent cache 03471 */ 03472 void 03473 usm_save_user(struct usmUser *user, const char *token, const char *type) 03474 { 03475 char line[4096]; 03476 char *cptr; 03477 03478 memset(line, 0, sizeof(line)); 03479 03480 sprintf(line, "%s %d %d ", token, user->userStatus, 03481 user->userStorageType); 03482 cptr = &line[strlen(line)]; /* the NULL */ 03483 cptr = 03484 read_config_save_octet_string(cptr, user->engineID, 03485 user->engineIDLen); 03486 *cptr++ = ' '; 03487 cptr = read_config_save_octet_string(cptr, (u_char *) user->name, 03488 (user->name == NULL) ? 0 : 03489 strlen(user->name) + 1); 03490 *cptr++ = ' '; 03491 cptr = read_config_save_octet_string(cptr, (u_char *) user->secName, 03492 (user->secName == NULL) ? 0 : 03493 strlen(user->secName) + 1); 03494 *cptr++ = ' '; 03495 cptr = 03496 read_config_save_objid(cptr, user->cloneFrom, user->cloneFromLen); 03497 *cptr++ = ' '; 03498 cptr = read_config_save_objid(cptr, user->authProtocol, 03499 user->authProtocolLen); 03500 *cptr++ = ' '; 03501 cptr = 03502 read_config_save_octet_string(cptr, user->authKey, 03503 user->authKeyLen); 03504 *cptr++ = ' '; 03505 cptr = read_config_save_objid(cptr, user->privProtocol, 03506 user->privProtocolLen); 03507 *cptr++ = ' '; 03508 cptr = 03509 read_config_save_octet_string(cptr, user->privKey, 03510 user->privKeyLen); 03511 *cptr++ = ' '; 03512 cptr = read_config_save_octet_string(cptr, user->userPublicString, 03513 (user->userPublicString == 03514 NULL) ? 0 : strlen((char *) 03515 user-> 03516 userPublicString) 03517 + 1); 03518 read_config_store(type, line); 03519 } 03520 03521 /* 03522 * usm_parse_user(): reads in a line containing a saved user profile 03523 * and returns a pointer to a newly created struct usmUser. 03524 */ 03525 struct usmUser * 03526 usm_read_user(char *line) 03527 { 03528 struct usmUser *user; 03529 size_t len; 03530 size_t expected_privKeyLen = 0; 03531 03532 user = usm_create_user(); 03533 if (user == NULL) 03534 return NULL; 03535 03536 user->userStatus = atoi(line); 03537 line = skip_token(line); 03538 user->userStorageType = atoi(line); 03539 line = skip_token(line); 03540 line = read_config_read_octet_string(line, &user->engineID, 03541 &user->engineIDLen); 03542 03543 /* 03544 * set the lcd entry for this engineID to the minimum boots/time 03545 * values so that its a known engineid and won't return a report pdu. 03546 * This is mostly important when receiving v3 traps so that the usm 03547 * will at least continue processing them. 03548 */ 03549 set_enginetime(user->engineID, user->engineIDLen, 1, 0, 0); 03550 03551 line = read_config_read_octet_string(line, (u_char **) & user->name, 03552 &len); 03553 line = read_config_read_octet_string(line, (u_char **) & user->secName, 03554 &len); 03555 SNMP_FREE(user->cloneFrom); 03556 user->cloneFromLen = 0; 03557 03558 line = 03559 read_config_read_objid(line, &user->cloneFrom, 03560 &user->cloneFromLen); 03561 03562 SNMP_FREE(user->authProtocol); 03563 user->authProtocolLen = 0; 03564 03565 line = read_config_read_objid(line, &user->authProtocol, 03566 &user->authProtocolLen); 03567 line = read_config_read_octet_string(line, &user->authKey, 03568 &user->authKeyLen); 03569 SNMP_FREE(user->privProtocol); 03570 user->privProtocolLen = 0; 03571 03572 line = read_config_read_objid(line, &user->privProtocol, 03573 &user->privProtocolLen); 03574 line = read_config_read_octet_string(line, &user->privKey, 03575 &user->privKeyLen); 03576 #ifndef NETSNMP_DISABLE_DES 03577 if (ISTRANSFORM(user->privProtocol, DESPriv)) { 03578 /* DES uses a 128 bit key, 64 bits of which is a salt */ 03579 expected_privKeyLen = 16; 03580 } 03581 #endif 03582 #ifdef HAVE_AES 03583 if (ISTRANSFORM(user->privProtocol, AESPriv)) { 03584 expected_privKeyLen = 16; 03585 } 03586 #endif 03587 /* For backwards compatibility */ 03588 if (user->privKeyLen > expected_privKeyLen) { 03589 user->privKeyLen = expected_privKeyLen; 03590 } 03591 03592 line = read_config_read_octet_string(line, &user->userPublicString, 03593 &len); 03594 return user; 03595 } 03596 03597 /* 03598 * snmpd.conf parsing routines 03599 */ 03600 void 03601 usm_parse_config_usmUser(const char *token, char *line) 03602 { 03603 struct usmUser *uptr; 03604 03605 uptr = usm_read_user(line); 03606 usm_add_user(uptr); 03607 } 03608 03609 03610 03611 03612 /*******************************************************************-o-****** 03613 * usm_set_password 03614 * 03615 * Parameters: 03616 * *token 03617 * *line 03618 * 03619 * 03620 * format: userSetAuthPass secname engineIDLen engineID pass 03621 * or: userSetPrivPass secname engineIDLen engineID pass 03622 * or: userSetAuthKey secname engineIDLen engineID KuLen Ku 03623 * or: userSetPrivKey secname engineIDLen engineID KuLen Ku 03624 * or: userSetAuthLocalKey secname engineIDLen engineID KulLen Kul 03625 * or: userSetPrivLocalKey secname engineIDLen engineID KulLen Kul 03626 * 03627 * type is: 1=passphrase; 2=Ku; 3=Kul. 03628 * 03629 * 03630 * ASSUMES Passwords are null-terminated printable strings. 03631 */ 03632 void 03633 usm_set_password(const char *token, char *line) 03634 { 03635 char *cp; 03636 char nameBuf[SNMP_MAXBUF]; 03637 u_char *engineID; 03638 size_t engineIDLen; 03639 struct usmUser *user; 03640 03641 cp = copy_nword(line, nameBuf, sizeof(nameBuf)); 03642 if (cp == NULL) { 03643 config_perror("invalid name specifier"); 03644 return; 03645 } 03646 03647 DEBUGMSGTL(("usm", "comparing: %s and %s\n", cp, WILDCARDSTRING)); 03648 if (strncmp(cp, WILDCARDSTRING, strlen(WILDCARDSTRING)) == 0) { 03649 /* 03650 * match against all engineIDs we know about 03651 */ 03652 cp = skip_token(cp); 03653 for (user = userList; user != NULL; user = user->next) { 03654 if (user->secName && strcmp(user->secName, nameBuf) == 0) { 03655 usm_set_user_password(user, token, cp); 03656 } 03657 } 03658 } else { 03659 cp = read_config_read_octet_string(cp, &engineID, &engineIDLen); 03660 if (cp == NULL) { 03661 config_perror("invalid engineID specifier"); 03662 return; 03663 } 03664 03665 user = usm_get_user(engineID, engineIDLen, nameBuf); 03666 if (user == NULL) { 03667 config_perror("not a valid user/engineID pair"); 03668 return; 03669 } 03670 usm_set_user_password(user, token, cp); 03671 } 03672 } 03673 03674 /* 03675 * uses the rest of LINE to configure USER's password of type TOKEN 03676 */ 03677 void 03678 usm_set_user_password(struct usmUser *user, const char *token, char *line) 03679 { 03680 char *cp = line; 03681 u_char *engineID = user->engineID; 03682 size_t engineIDLen = user->engineIDLen; 03683 03684 u_char **key; 03685 size_t *keyLen; 03686 u_char userKey[SNMP_MAXBUF_SMALL]; 03687 size_t userKeyLen = SNMP_MAXBUF_SMALL; 03688 u_char *userKeyP = userKey; 03689 int type, ret; 03690 03691 /* 03692 * Retrieve the "old" key and set the key type. 03693 */ 03694 if (!token) { 03695 return; 03696 } else if (strcmp(token, "userSetAuthPass") == 0) { 03697 key = &user->authKey; 03698 keyLen = &user->authKeyLen; 03699 type = 0; 03700 } else if (strcmp(token, "userSetPrivPass") == 0) { 03701 key = &user->privKey; 03702 keyLen = &user->privKeyLen; 03703 type = 0; 03704 } else if (strcmp(token, "userSetAuthKey") == 0) { 03705 key = &user->authKey; 03706 keyLen = &user->authKeyLen; 03707 type = 1; 03708 } else if (strcmp(token, "userSetPrivKey") == 0) { 03709 key = &user->privKey; 03710 keyLen = &user->privKeyLen; 03711 type = 1; 03712 } else if (strcmp(token, "userSetAuthLocalKey") == 0) { 03713 key = &user->authKey; 03714 keyLen = &user->authKeyLen; 03715 type = 2; 03716 } else if (strcmp(token, "userSetPrivLocalKey") == 0) { 03717 key = &user->privKey; 03718 keyLen = &user->privKeyLen; 03719 type = 2; 03720 } else { 03721 /* 03722 * no old key, or token was not recognized 03723 */ 03724 return; 03725 } 03726 03727 if (*key) { 03728 /* 03729 * (destroy and) free the old key 03730 */ 03731 memset(*key, 0, *keyLen); 03732 SNMP_FREE(*key); 03733 } 03734 03735 if (type == 0) { 03736 /* 03737 * convert the password into a key 03738 */ 03739 if (cp == NULL) { 03740 config_perror("missing user password"); 03741 return; 03742 } 03743 ret = generate_Ku(user->authProtocol, user->authProtocolLen, 03744 (u_char *) cp, strlen(cp), userKey, &userKeyLen); 03745 03746 if (ret != SNMPERR_SUCCESS) { 03747 config_perror("setting key failed (in sc_genKu())"); 03748 return; 03749 } 03750 } else if (type == 1) { 03751 cp = read_config_read_octet_string(cp, &userKeyP, &userKeyLen); 03752 03753 if (cp == NULL) { 03754 config_perror("invalid user key"); 03755 return; 03756 } 03757 } 03758 03759 if (type < 2) { 03760 *key = (u_char *) malloc(SNMP_MAXBUF_SMALL); 03761 *keyLen = SNMP_MAXBUF_SMALL; 03762 ret = generate_kul(user->authProtocol, user->authProtocolLen, 03763 engineID, engineIDLen, 03764 userKey, userKeyLen, *key, keyLen); 03765 if (ret != SNMPERR_SUCCESS) { 03766 config_perror("setting key failed (in generate_kul())"); 03767 return; 03768 } 03769 03770 /* 03771 * (destroy and) free the old key 03772 */ 03773 memset(userKey, 0, sizeof(userKey)); 03774 03775 } else { 03776 /* 03777 * the key is given, copy it in 03778 */ 03779 cp = read_config_read_octet_string(cp, key, keyLen); 03780 03781 if (cp == NULL) { 03782 config_perror("invalid localized user key"); 03783 return; 03784 } 03785 } 03786 } /* end usm_set_password() */