From: ysvenkat Date: Wed, 6 Jan 2010 02:19:12 +0000 (+0000) Subject: Added support for reporting usage metrics. X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/commitdiff_plain/9f2c8cb950fea61c599edeb9721aca66f4bd61f6 Added support for reporting usage metrics. --- diff --git a/openssh/Makefile.in b/openssh/Makefile.in index 28aeee6..97fba2d 100644 --- a/openssh/Makefile.in +++ b/openssh/Makefile.in @@ -91,7 +91,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ gss-serv-gsi.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \ - roaming_common.o + roaming_common.o ssh-globus-usage.o MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5 diff --git a/openssh/auth.c b/openssh/auth.c index 010e550..19253fe 100644 --- a/openssh/auth.c +++ b/openssh/auth.c @@ -71,6 +71,9 @@ #endif #include "monitor_wrap.h" +#include "version.h" +#include "ssh-globus-usage.h" + /* import */ extern ServerOptions options; extern int use_privsep; @@ -292,6 +295,21 @@ auth_log(Authctxt *authctxt, int authenticated, char *method, char *info) if (authenticated == 0 && !authctxt->postponed) audit_event(audit_classify_auth(method)); #endif + if (authenticated) { + char *userdn = NULL; + char *mech_name = NULL; + ssh_gssapi_get_client_info(&userdn, &mech_name); + debug("REPORTING (%s) (%s) (%s) (%s) (%s) (%s) (%s)", + SSH_RELEASE, SSLeay_version(SSLEAY_VERSION), + method, mech_name?mech_name:"NULL", get_remote_ipaddr(), + (authctxt->user && authctxt->user[0])? + authctxt->user : "unknown", + userdn?userdn:"NULL"); + ssh_globus_send_usage_metrics(SSH_RELEASE, + SSLeay_version(SSLEAY_VERSION), + method, mech_name, get_remote_ipaddr(), + authctxt->user, userdn); + } } /* diff --git a/openssh/configure.ac b/openssh/configure.ac index af183e5..f24e133 100644 --- a/openssh/configure.ac +++ b/openssh/configure.ac @@ -1195,6 +1195,19 @@ AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN, 1, [Define if your libraries define login()])]) AC_CHECK_FUNCS(fmt_scaled logout updwtmp logwtmp) +dnl +dnl Check for globus_usage_stats_send +dnl +AC_SEARCH_LIBS(globus_usage_stats_send, + globus_usage globus_usage_${globus_flavor_type}, + AC_DEFINE([HAVE_GLOBUS_USAGE], 1, [Have Globus Usage])) +dnl +dnl Check for globus_usage_stats_send_array +dnl +AC_SEARCH_LIBS(globus_usage_stats_send_array, + globus_usage globus_usage_${globus_flavor_type}, + AC_DEFINE([HAVE_GLOBUS_USAGE_SEND_ARRAY], 1, [Have Globus Usage send_array])) + AC_FUNC_STRFTIME # Check for ALTDIRFUNC glob() extension diff --git a/openssh/gss-serv.c b/openssh/gss-serv.c index 7cbf8e2..6fbc09d 100644 --- a/openssh/gss-serv.c +++ b/openssh/gss-serv.c @@ -608,4 +608,10 @@ ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { return ok; } +void +ssh_gssapi_get_client_info(char **userdn, char **mech) { + *userdn = gssapi_client.displayname.value; + *mech = gssapi_client.mech->name; +} + #endif diff --git a/openssh/servconf.c b/openssh/servconf.c index bb2f9d6..9369476 100644 --- a/openssh/servconf.c +++ b/openssh/servconf.c @@ -143,6 +143,8 @@ initialize_server_options(ServerOptions *options) options->tcp_rcv_buf_poll = -1; options->hpn_disabled = -1; options->hpn_buffer_size = -1; + options->disable_usage_stats = 0; + options->usage_stats_targets = NULL; } void @@ -342,7 +344,6 @@ fill_default_server_options(ServerOptions *options) options->compression = 0; } #endif - } /* Keyword tokens. */ @@ -383,6 +384,7 @@ typedef enum { sUsePrivilegeSeparation, sAllowAgentForwarding, sZeroKnowledgePasswordAuthentication, sNoneEnabled, sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize, + sDisUsageStats, sUsageStatsTarg, sDeprecated, sUnsupported } ServerOpCodes; @@ -528,6 +530,8 @@ static struct { { "hpndisabled", sHPNDisabled }, { "hpnbuffersize", sHPNBufferSize }, { "tcprcvbufpoll", sTcpRcvBufPoll }, + { "disable_usage_stats", sDisUsageStats, SSHCFG_GLOBAL}, + { "usage_stats_target", sUsageStatsTarg, SSHCFG_GLOBAL}, { NULL, sBadOption, 0 } }; @@ -1462,6 +1466,39 @@ process_server_config_line(ServerOptions *options, char *line, *charptr = xstrdup(arg); break; + case sDisUsageStats: + charptr = &options->chroot_directory; + + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing value.", + filename, linenum); + if (!strcasecmp(arg, "true") || + !strcasecmp(arg, "enabled") || + !strcasecmp(arg, "yes") || + !strcasecmp(arg, "on") || + !strcasecmp(arg, "1")) + options->disable_usage_stats = 1; + else if (!strcasecmp(arg, "false") || + !strcasecmp(arg, "disabled") || + !strcasecmp(arg, "no") || + !strcasecmp(arg, "off") || + !strcasecmp(arg, "0")) + options->disable_usage_stats = 0; + else + fatal("Incorrect value for disable_usage_stats"); + break; + + case sUsageStatsTarg: + charptr = &options->chroot_directory; + + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing value.", + filename, linenum); + options->usage_stats_targets = xstrdup(arg); + break; + case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); diff --git a/openssh/servconf.h b/openssh/servconf.h index 2c9f00e..4ef1d36 100644 --- a/openssh/servconf.h +++ b/openssh/servconf.h @@ -167,6 +167,10 @@ typedef struct { int num_permitted_opens; char *chroot_directory; + + int disable_usage_stats; + + char *usage_stats_targets; } ServerOptions; void initialize_server_options(ServerOptions *); diff --git a/openssh/ssh-globus-usage.c b/openssh/ssh-globus-usage.c new file mode 100644 index 0000000..3e30504 --- /dev/null +++ b/openssh/ssh-globus-usage.c @@ -0,0 +1,386 @@ +/* + * Copyright 2009 The Board of Trustees of the University + * of Illinois. See the LICENSE file for detailed license information. + * + * Portions, specifically log_usage_stats(), ssh_usage_stats_init(), + * ssh_usage_stats_close(), ssh_usage_ent_s, ssh_usage_tag_e and + * TAG #defines were based on those from Usage Metrics portions of: + * gridftp/server/source/globus_i_gfs_log.c + * + * Copyright 1999-2006 University of Chicago + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "log.h" +#include "ssh-globus-usage.h" + +#ifdef HAVE_GLOBUS_USAGE + +static globus_list_t *usage_handle_list = NULL; + +#define SSH_GLOBUS_USAGE_ID 12 +#define SSH_GLOBUS_USAGE_VER 0 + +#define SSH_GLOBUS_DEFAULT_TAGLIST "VvMm" +#define SSH_GLOBUS_ALL_TAGLIST "VvMmIuU" +#define SSH_GLOBUS_TAGCOUNT 25 + +typedef enum ssh_usage_tag_e +{ + SSH_GLOBUS_USAGE_SSH_VER = 'V', + SSH_GLOBUS_USAGE_SSL_VER = 'v', + SSH_GLOBUS_USAGE_METHOD = 'M', + SSH_GLOBUS_USAGE_MECHANISM = 'm', + SSH_GLOBUS_USAGE_CLIENTIP = 'I', + SSH_GLOBUS_USAGE_USERNAME = 'u', + SSH_GLOBUS_USAGE_USERDN = 'U' + /* !! ADD to ALL_TAGLIST above and to globus_usage_stats_send() + invocation below when adding here */ +} ssh_usage_tag_t; + +typedef struct ssh_usage_ent_s +{ + globus_usage_stats_handle_t handle; + char * target; + char * taglist; +} ssh_usage_ent_t; + + +globus_result_t +ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets) +{ + globus_result_t result; + char * target_str = NULL; + char * ptr = ptr; + char * target = NULL; + char * entry = NULL; + globus_list_t * list = NULL; + ssh_usage_ent_t * usage_ent = NULL; + + if (disable_usage_stats) + return GLOBUS_SUCCESS; + + result = globus_module_activate(GLOBUS_USAGE_MODULE); + if (result != GLOBUS_SUCCESS) + { + error("ERROR: couldn't activate USAGE module"); + return result; + } + + if (!usage_stats_targets || + !strcasecmp(usage_stats_targets, "default")) + target_str = strdup(CILOGON_COLLECTOR); + else + target_str = strdup(usage_stats_targets); + + if (target_str == NULL) + { + error("ERROR: strdup failure for target_str"); + goto error; + } + debug("Processing usage_stats_target (%s)\n", target_str); + + if(target_str && strchr(target_str, '!')) + { + target = target_str; + + do { + usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t)); + if (usage_ent == NULL) + { + error("ERROR: couldn't allocate for ssh_usage_ent_t"); + goto error; + } + + if ((ptr = strchr(target, ',')) != NULL) + *ptr = '\0'; + + entry = strdup(target); + if (entry == NULL) + { + error("ERROR: strdup failure for target"); + goto error; + } + + if (ptr) + target = ptr + 1; + else + target = NULL; + + if((ptr = strchr(entry, '!')) != NULL) + { + *ptr = '\0'; + usage_ent->taglist = strdup(ptr + 1); + if (usage_ent->taglist == NULL) + { + error("ERROR: strdup failure for taglist"); + goto error; + } + if(strlen(usage_ent->taglist) > SSH_GLOBUS_TAGCOUNT) + { + usage_ent->taglist[SSH_GLOBUS_TAGCOUNT + 1] = '\0'; + } + } + else + { + usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); + if (usage_ent->taglist == NULL) + { + error("ERROR: couldn't allocate for taglist"); + goto error; + } + } + + if(strcasecmp(usage_ent->taglist, "default") == 0) + { + free(usage_ent->taglist); + usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); + if (usage_ent->taglist == NULL) + { + error("ERROR: couldn't allocate for taglist"); + goto error; + } + } + else if(strcasecmp(usage_ent->taglist, "all") == 0) + { + free(usage_ent->taglist); + usage_ent->taglist = strdup(SSH_GLOBUS_ALL_TAGLIST); + if (usage_ent->taglist == NULL) + { + error("ERROR: couldn't allocate for taglist"); + goto error; + } + } + + usage_ent->target = entry; + + globus_list_insert(&usage_handle_list, usage_ent); + } + while(target != NULL); + + free(target_str); + } + else + { + usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t)); + if (usage_ent == NULL) + { + error("ERROR: couldn't allocate for usage_ent"); + goto error; + } + + usage_ent->target = target_str; + usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); + if (usage_ent->taglist == NULL) + { + error("ERROR: couldn't allocate for taglist"); + goto error; + } + + globus_list_insert(&usage_handle_list, usage_ent); + } + + + for(list = usage_handle_list; + !globus_list_empty(list); + list = globus_list_rest(list)) + { + usage_ent = (ssh_usage_ent_t *) globus_list_first(list); + + usage_ent->handle = NULL; + debug("USAGE: Initializing (%s) (%s)", usage_ent->target?:"NULL", + usage_ent->taglist?:"NULL"); + result = globus_usage_stats_handle_init( + &usage_ent->handle, + SSH_GLOBUS_USAGE_ID, + SSH_GLOBUS_USAGE_VER, + usage_ent->target); + } + + return result; + +error: + if (target_str) + { + free(target_str); + target_str = NULL; + } + if (entry) + { + free(target_str); + target_str = NULL; + } + return GLOBUS_FAILURE; +} + +void +ssh_usage_stats_close(int disable_usage_stats) +{ + globus_list_t *list; + + if (disable_usage_stats) + return; + + list = usage_handle_list; + + while(!globus_list_empty(list)) + { + ssh_usage_ent_t *usage_ent; + + usage_ent = (ssh_usage_ent_t *) + globus_list_remove(&list, list); + + if(usage_ent) + { + if(usage_ent->handle) + { + globus_usage_stats_handle_destroy(usage_ent->handle); + } + if(usage_ent->target) + { + free(usage_ent->target); + } + if(usage_ent->taglist) + { + free(usage_ent->taglist); + } + free(usage_ent); + } + } + usage_handle_list = NULL; +} + +static void +log_usage_stats(char *ssh_release, const char *ssl_release, + char *method, char *mechanism, const char *clientip, + char *username, char *userdn) +{ + globus_result_t result; + globus_list_t * list; + ssh_usage_ent_t * usage_ent; + char * keys[SSH_GLOBUS_TAGCOUNT]; + char * values[SSH_GLOBUS_TAGCOUNT]; + char * ptr; + char * key; + char * value; + int i = 0; + char * save_taglist = NULL; + + for(list = usage_handle_list; + !globus_list_empty(list); + list = globus_list_rest(list)) + { + usage_ent = (ssh_usage_ent_t *) globus_list_first(list); + + if(!usage_ent || usage_ent->handle == NULL) + return; + + if(save_taglist == NULL || + strcmp(save_taglist, usage_ent->taglist) != 0) + { + save_taglist = usage_ent->taglist; + + ptr = usage_ent->taglist; + i = 0; + while(ptr && *ptr) + { + switch(*ptr) + { + case SSH_GLOBUS_USAGE_SSH_VER: + key = "SSH_VER"; + value = ssh_release; + break; + + case SSH_GLOBUS_USAGE_SSL_VER: + key = "SSL_VER"; + value = (char *) ssl_release; + break; + + case SSH_GLOBUS_USAGE_METHOD: + key = "METHOD"; + value = method; + break; + + case SSH_GLOBUS_USAGE_MECHANISM: + key = "MECH"; + value = mechanism?:""; + break; + + case SSH_GLOBUS_USAGE_CLIENTIP: + key = "CLIENTIP"; + value = (char *) clientip?:""; + break; + + case SSH_GLOBUS_USAGE_USERNAME: + key = "USER"; + value = username?:""; + break; + + case SSH_GLOBUS_USAGE_USERDN: + key = "USERDN"; + value = userdn?:""; + break; + + default: + key = NULL; + value = NULL; + break; + } + + if(key != NULL && value != NULL) + { + keys[i] = key; + values[i] = value; + i++; + } + + ptr++; + } + } + +#ifdef HAVE_GLOBUS_USAGE_SEND_ARRAY + result = globus_usage_stats_send_array( + usage_ent->handle, i, keys, values); +#else + if (i) + result = globus_usage_stats_send( + usage_ent->handle, i, + i>0?keys[0]:NULL, i>0?values[0]:NULL, + i>1?keys[1]:NULL, i>1?values[1]:NULL, + i>2?keys[2]:NULL, i>2?values[2]:NULL, + i>3?keys[3]:NULL, i>3?values[3]:NULL, + i>4?keys[4]:NULL, i>4?values[4]:NULL, + i>5?keys[5]:NULL, i>5?values[5]:NULL, + i>6?keys[6]:NULL, i>6?values[6]:NULL); +#endif /* HAVE_GLOBUS_USAGE_SEND_ARRAY */ + } + + return; +} +#endif /* HAVE_GLOBUS_USAGE */ + +void +ssh_globus_send_usage_metrics(char *ssh_release, const char *ssl_release, + char *method, char *mechanism, const char *client_ip, + char *username, char *userdn) +{ +#ifdef HAVE_GLOBUS_USAGE + + log_usage_stats(ssh_release, ssl_release, method, mechanism, + client_ip, username, userdn); + +#endif /* HAVE_GLOBUS_USAGE */ +} diff --git a/openssh/ssh-globus-usage.h b/openssh/ssh-globus-usage.h new file mode 100644 index 0000000..c94dcd4 --- /dev/null +++ b/openssh/ssh-globus-usage.h @@ -0,0 +1,46 @@ +/* + * Copyright 2009 The Board of Trustees of the University + * of Illinois. See the LICENSE file for detailed license information. + * + * Portions, specifically ssh_usage_stats_init(), ssh_usage_stats_close() + * were based on those from: gridftp/server/source/globus_i_gfs_log.h + * Copyright 1999-2006 University of Chicago + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SSH_GLOBUS_USAGE_H +#define __SSH_GLOBUS_USAGE_H + +#include "includes.h" + +#ifdef HAVE_GLOBUS_USAGE + +#include "globus_usage.h" + +#define CILOGON_COLLECTOR "usage-stats.cilogon.org:4810" + +globus_result_t +ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets); + +void +ssh_usage_stats_close(int disable_usage_stats); + +#endif /* HAVE_GLOBUS_USAGE */ + +void +ssh_globus_send_usage_metrics(char *ssh_release, const char *ssl_release, + char *method, char *mechanism, const char *client_ip, + char *username, char *userdn); + +#endif /* __SSH_GLOBUS_USAGE_H */ diff --git a/openssh/ssh-gss.h b/openssh/ssh-gss.h index f0009c8..8ff6869 100644 --- a/openssh/ssh-gss.h +++ b/openssh/ssh-gss.h @@ -170,6 +170,7 @@ char *ssh_gssapi_server_mechanisms(void); int ssh_gssapi_oid_table_ok(); int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); +void ssh_gssapi_get_client_info(char **userdn, char **mech); #endif /* GSSAPI */ #endif /* _SSH_GSS_H */ diff --git a/openssh/sshd.c b/openssh/sshd.c index 12000b1..b19bdac 100644 --- a/openssh/sshd.c +++ b/openssh/sshd.c @@ -119,6 +119,7 @@ #include "monitor_wrap.h" #include "roaming.h" #include "version.h" +#include "ssh-globus-usage.h" #ifdef USE_SECURITY_SESSION_API #include @@ -1488,6 +1489,13 @@ main(int ac, char **av) /* Fill in default values for those options not explicitly set. */ fill_default_server_options(&options); +#ifdef HAVE_GLOBUS_USAGE + if (ssh_usage_stats_init(options.disable_usage_stats, + options.usage_stats_targets) != GLOBUS_SUCCESS) { + fatal("Error initializing Globus Usage Metrics"); + } +#endif /* HAVE_GLOBUS_USAGE */ + /* challenge-response is implemented via keyboard interactive */ if (options.challenge_response_authentication) options.kbd_interactive_authentication = 1;