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