blob: 57c7e85f7087673cda77f79b9fc555f966d6018a [file] [log] [blame]
/*
* snmp_parse_args.c
*/
#include <config.h>
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <sys/types.h>
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ctype.h>
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if TIME_WITH_SYS_TIME
# ifdef WIN32
# include <sys/timeb.h>
# else
# include <sys/time.h>
# endif
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#if HAVE_WINSOCK_H
#include <winsock.h>
#endif
#if HAVE_NETDB_H
#include <netdb.h>
#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include "asn1.h"
#include "snmp_api.h"
#include "snmp_impl.h"
#include "snmp_client.h"
#include "mib.h"
#include "snmp.h"
#include "scapi.h"
#include "keytools.h"
#include "snmp_parse_args.h"
#include "snmp_logging.h"
#include "version.h"
#include "system.h"
#include "parse.h"
#include "read_config.h"
#include "snmp_debug.h"
#include "snmpv3.h"
#include "default_store.h"
int random_access = 0;
void usage(void);
#define USM_AUTH_PROTO_MD5_LEN 10
static oid usmHMACMD5AuthProtocol[] = { 1,3,6,1,6,3,10,1,1,2 };
#define USM_AUTH_PROTO_SHA_LEN 10
static oid usmHMACSHA1AuthProtocol[] = { 1,3,6,1,6,3,10,1,1,3 };
#define USM_PRIV_PROTO_DES_LEN 10
static oid usmDESPrivProtocol[] = { 1,3,6,1,6,3,10,1,2,2 };
void
snmp_parse_args_usage(FILE *outf)
{
fprintf(outf, "[-v 1|2c|3] [-h] [-H] [-d] [-q] [-R] [-D] [-m <MIBS>] [-M <MIDDIRS>] [-p <P>] [-t <T>] [-r <R>] ");
fprintf(outf, "[-T <B> <T>] [-e <E>] [-E <E>] [-n <N>] [-u <U>] [-l <L>] [-a <A>] [-A <P>] [-x <X>] [-X <P>] <hostname> {<community>}");
}
void
snmp_parse_args_descriptions(FILE *outf)
{
fprintf(outf, " -v 1|2c|3\tspecifies snmp version to use.\n");
fprintf(outf, " -h\t\tthis help message.\n");
fprintf(outf, " -H\t\tDisplay configuration file directives understood.\n");
fprintf(outf, " -V\t\tdisplay version number.\n");
fprintf(outf, " -d\t\tdump input/output packets.\n");
fprintf(outf, " -q\t\tquick print output for easier parsing ability.\n");
fprintf(outf, " -f\t\tprint full object identifiers on output.\n");
fprintf(outf, " -s\t\tprint only last element of object identifiers.\n");
fprintf(outf, " -S\t\tmodule id plus last element of object identifiers.\n");
fprintf(outf, " -R\t\tuse \"random access\" to the mib tree.\n");
fprintf(outf, " -D[TOKEN,...]\t\tturn on debugging output, optionally by the list of TOKENs.\n");
fprintf(outf, " -m <MIBS>\tuse MIBS list instead of the default mib list.\n");
fprintf(outf, " -M <MIBDIRS>\tuse MIBDIRS as the location to look for mibs.\n");
fprintf(outf, " -p <P>\tuse port P instead of the default port.\n");
fprintf(outf, " -t <T>\tset the request timeout to T.\n");
fprintf(outf, " -r <R>\tset the number of retries to R.\n");
fprintf(outf,
" -T <B> <T>\tset the destination engine boots/time for v3 requests.\n");
fprintf(outf, " -e <E>\tsecurity engine ID (e.g., 800000020109840301).\n");
fprintf(outf, " -E <E>\tcontext engine ID (e.g., 800000020109840301).\n");
fprintf(outf, " -n <N>\tcontext name (e.g., bridge1).\n");
fprintf(outf, " -u <U>\tsecurity name (e.g., bert).\n");
fprintf(outf, " -l <L>\tsecurity level (noAuthNoPriv|authNoPriv|authPriv).\n");
fprintf(outf, " -a <A>\tauthentication protocol (MD5|SHA)\n");
fprintf(outf, " -A <P>\tauthentication protocol pass phrase.\n");
fprintf(outf, " -x <X>\tprivacy protocol (DES).\n");
fprintf(outf, " -X <P>\tprivacy protocol pass phrase\n");
fprintf(outf, " -P <MIBOPTS>\tToggle various defaults controlling mib parsing:\n");
snmp_mib_toggle_options_usage("\t\t ", outf);
}
#define BUF_SIZE 512
int
snmp_parse_args(int argc,
char *argv[],
struct snmp_session *session)
{
int arg;
char *psz, *cp;
char *Apsz = NULL;
char *Xpsz = NULL;
u_char buf[BUF_SIZE];
size_t bsize;
/* initialize session to default values */
snmp_sess_init( session );
/* get the options */
for(arg = 1; (arg < argc) && (argv[arg][0] == '-'); arg++){
switch(argv[arg][1]){
case 'd':
snmp_set_dump_packet(1);
break;
case 'R':
random_access = 1;
break;
case 'q':
snmp_set_quick_print(1);
break;
case 'D':
debug_register_tokens(&argv[arg][2]);
snmp_set_do_debugging(!snmp_get_do_debugging());
break;
case 'm':
if (argv[arg][2] != 0)
setenv("MIBS",&argv[arg][2], 1);
else if (++arg < argc)
setenv("MIBS",argv[arg], 1);
else {
fprintf(stderr,"Need MIBS after -m flag.\n");
usage();
exit(1);
}
break;
case 'M':
if (argv[arg][2] != 0)
setenv("MIBDIRS",&argv[arg][2], 1);
else if (++arg < argc)
setenv("MIBDIRS",argv[arg], 1);
else {
fprintf(stderr,"Need MIBDIRS after -M flag.\n");
usage();
exit(1);
}
break;
case 'f':
snmp_set_full_objid(1);
break;
case 's':
snmp_set_suffix_only(1);
break;
case 'S':
snmp_set_suffix_only(2);
break;
case 'p':
if (isdigit(argv[arg][2]))
session->remote_port = atoi(&(argv[arg][2]));
else if ((++arg<argc) && isdigit(argv[arg][0]))
session->remote_port = atoi(argv[arg]);
else {
fprintf(stderr,"Need port number after -p flag.\n");
usage();
exit(1);
}
break;
case 't':
if (isdigit(argv[arg][2]))
session->timeout = atoi(&(argv[arg][2])) * 1000000L;
else if ((++arg<argc) && isdigit(argv[arg][0]))
session->timeout = atoi(argv[arg]) * 1000000L;
else {
fprintf(stderr,"Need time in seconds after -t flag.\n");
usage();
exit(1);
}
break;
case 'r':
if (isdigit(argv[arg][2]))
session->retries = atoi(&(argv[arg][2]));
else if ((++arg<argc) && isdigit(argv[arg][0]))
session->retries = atoi(argv[arg]);
else {
fprintf(stderr,"Need number of retries after -r flag.\n");
usage();
exit(1);
}
break;
case 'T':
if (isdigit(argv[arg][2]))
session->engineBoots = (u_long)(atol(&(argv[arg][2])));
else if ((++arg<argc) && isdigit(argv[arg][0]))
session->engineBoots = (u_long)(atol(argv[arg]));
else {
fprintf(stderr,"Need engine boots value after -T flag.\n");
usage();
exit(1);
}
if ((++arg<argc) && isdigit(argv[arg][0]))
session->engineTime = (u_long)(atol(argv[arg]));
else {
fprintf(stderr,"Need engine time value after -T flag.\n");
usage();
exit(1);
}
break;
case 'V':
fprintf(stderr,"UCD-snmp version: %s\n", VersionInfo);
exit(0);
case 'v':
if (argv[arg][2] != 0)
psz = &(argv[arg][2]);
else
psz = argv[++arg];
if( psz == NULL) {
fprintf(stderr,"Need version value after -v flag. \n");
usage();
exit(1);
}
if (!strcmp(psz,"1")) {
session->version = SNMP_VERSION_1;
} else if (!strcasecmp(psz,"2c")) {
session->version = SNMP_VERSION_2c;
} else if (!strcasecmp(psz,"3")) {
session->version = SNMP_VERSION_3;
} else {
fprintf(stderr,"Invalid version specified after -v flag: %s\n", psz);
usage();
exit(1);
}
break;
case 'e':
if (argv[arg][2] != 0)
psz = &(argv[arg][2]);
else
psz = argv[++arg];
if( psz == NULL) {
fprintf(stderr,"Need engine ID value after -e flag. \n");
usage();
exit(1);
}
if ((bsize = hex_to_binary(psz,buf)) <= 0) {
fprintf(stderr,"Need engine ID value after -e flag. \n");
usage();
exit(1);
}
session->securityEngineID = (u_char *)malloc(bsize);
memcpy(session->securityEngineID, buf, bsize);
session->securityEngineIDLen = bsize;
break;
case 'E':
if (argv[arg][2] != 0)
psz = &(argv[arg][2]);
else
psz = argv[++arg];
if( psz == NULL) {
fprintf(stderr,"Need engine ID value after -E flag. \n");
usage();
exit(1);
}
if ((bsize = hex_to_binary(psz,buf)) <= 0) {
fprintf(stderr,"Need engine ID value after -E flag. \n");
usage();
exit(1);
}
session->contextEngineID = (u_char *)malloc(bsize);
memcpy(session->contextEngineID, buf, bsize);
session->contextEngineIDLen = bsize;
break;
case 'n':
if (argv[arg][2] != 0)
psz = &(argv[arg][2]);
else
psz = argv[++arg];
if( psz == NULL) {
fprintf(stderr,"Need context name value after -n flag. \n");
usage();
exit(1);
}
session->contextName = strdup(psz);
session->contextNameLen = strlen(psz);
break;
case 'u':
if (argv[arg][2] != 0)
psz = &(argv[arg][2]);
else
psz = argv[++arg];
if( psz == NULL) {
fprintf(stderr,"Need security user name value after -u flag. \n");
usage();
exit(1);
}
session->securityName = strdup(psz);
session->securityNameLen = strlen(psz);
break;
case 'l':
if (argv[arg][2] != 0)
psz = &(argv[arg][2]);
else
psz = argv[++arg];
if( psz == NULL) {
fprintf(stderr,"Need security level value after -l flag. \n");
usage();
exit(1);
}
if (!strcmp(psz,"noAuthNoPriv") || !strcmp(psz,"1") ||
!strcmp(psz,"nanp")) {
session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
} else if (!strcmp(psz,"authNoPriv") || !strcmp(psz,"2") ||
!strcmp(psz,"anp")) {
session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
} else if (!strcmp(psz,"authPriv") || !strcmp(psz,"3") ||
!strcmp(psz,"ap")) {
session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
} else {
fprintf(stderr,"Invalid security level specified after -l flag: %s\n", psz);
usage();
exit(1);
}
break;
case 'a':
if (argv[arg][2] != 0)
psz = &(argv[arg][2]);
else
psz = argv[++arg];
if( psz == NULL) {
fprintf(stderr,"Need authentication protocol value after -a flag. \n");
usage();
exit(1);
}
if (!strcmp(psz,"MD5")) {
session->securityAuthProto = usmHMACMD5AuthProtocol;
session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
} else if (!strcmp(psz,"SHA")) {
session->securityAuthProto = usmHMACSHA1AuthProtocol;
session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
} else {
fprintf(stderr,"Invalid authentication protocol specified after -a flag: %s\n", psz);
usage();
exit(1);
}
break;
case 'x':
if (argv[arg][2] != 0)
psz = &(argv[arg][2]);
else
psz = argv[++arg];
if( psz == NULL) {
fprintf(stderr,"Need privacy protocol value after -x flag. \n");
usage();
exit(1);
}
if (!strcmp(psz,"DES")) {
session->securityPrivProto = usmDESPrivProtocol;
session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
} else {
fprintf(stderr,"Invalid privacy protocol specified after -x flag: %s\n", psz);
usage();
exit(1);
}
break;
case 'A':
if (argv[arg][2] != 0)
Apsz = &(argv[arg][2]);
else
Apsz = argv[++arg];
if( Apsz == NULL) {
fprintf(stderr,"Need authentication pass phrase value after -A flag. \n");
usage();
exit(1);
}
break;
case 'X':
if (argv[arg][2] != 0)
Xpsz = &(argv[arg][2]);
else
Xpsz = argv[++arg];
if( Xpsz == NULL) {
fprintf(stderr,"Need privacy pass phrase value after -X flag. \n");
usage();
exit(1);
}
break;
case 'P':
if (argv[arg][2] != 0)
cp = &argv[arg][2];
else if (++arg<argc)
cp = &argv[arg][2];
else {
fprintf(stderr,"Need option arguments after -P flag.\n");
usage();
exit(1);
}
cp = snmp_mib_toggle_options(cp);
if (cp != NULL) {
fprintf(stderr,"Unknown parsing option passed to -P: %c.\n", *cp);
usage();
exit(1);
}
break;
case 'h':
usage();
exit(0);
break;
case 'H':
init_snmp("snmpapp");
fprintf(stderr, "Configuration directives understood:\n");
read_config_print_usage(" ");
exit(0);
default:
/* This should be removed to support options in clients that
have more parameters than the defaults above! */
fprintf(stderr, "invalid option: -%c\n", argv[arg][1]);
usage();
exit(1);
break;
}
}
/* read in MIB database and initialize the snmp library*/
init_snmp("snmpapp");
if (session->version == SNMP_DEFAULT_VERSION) {
session->version = ds_get_int(DS_LIBRARY_ID, DS_LIB_SNMPVERSION);
}
/* make our engineID something other than what the localhost might
* be using, otherwise the automatic v3 time-synchronization won't work */
setup_engineID(NULL, "a bogus text string");
/* make master key from pass phrases */
if (Apsz) {
session->securityAuthKeyLen = USM_AUTH_KU_LEN;
if (generate_Ku(session->securityAuthProto,
session->securityAuthProtoLen,
(u_char *)Apsz, strlen(Apsz),
session->securityAuthKey,
&session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
fprintf(stderr,"Error generating Ku from authentication pass phrase. \n");
usage();
exit(1);
}
}
if (Xpsz) {
session->securityPrivKeyLen = USM_PRIV_KU_LEN;
if (generate_Ku(session->securityAuthProto,
session->securityAuthProtoLen,
(u_char *)Xpsz, strlen(Xpsz),
session->securityPrivKey,
&session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
fprintf(stderr,"Error generating Ku from privacy pass phrase. \n");
usage();
exit(1);
}
}
/* get the hostname */
if (arg == argc) {
fprintf(stderr,"No hostname specified.\n");
usage();
exit(1);
}
session->peername = argv[arg++]; /* hostname */
/* get community */
if ((session->version == SNMP_VERSION_1) ||
(session->version == SNMP_VERSION_2c)) {
/* v1 and v2c - so get community string */
if (arg == argc) {
fprintf(stderr,"No community name specified.\n");
usage();
exit(1);
}
session->community = (unsigned char *)argv[arg];
session->community_len = strlen((char *)argv[arg]);
arg++;
}
return arg;
}
oid
*snmp_parse_oid(char *argv,
oid *root,
size_t *rootlen)
{
size_t savlen = *rootlen;
if (random_access) {
if (get_node(argv,root,rootlen)) {
return root;
}
} else {
if (read_objid(argv,root,rootlen)) {
return root;
}
*rootlen = savlen;
if (get_node(argv,root,rootlen)) {
return root;
}
}
snmp_errno = SNMPERR_UNKNOWN_OBJID;
return NULL;
}