]> andersk Git - gssapi-openssh.git/commitdiff
Added support for reporting usage metrics.
authorysvenkat <ysvenkat>
Wed, 6 Jan 2010 02:19:12 +0000 (02:19 +0000)
committerysvenkat <ysvenkat>
Wed, 6 Jan 2010 02:19:12 +0000 (02:19 +0000)
openssh/Makefile.in
openssh/auth.c
openssh/configure.ac
openssh/gss-serv.c
openssh/servconf.c
openssh/servconf.h
openssh/ssh-globus-usage.c [new file with mode: 0644]
openssh/ssh-globus-usage.h [new file with mode: 0644]
openssh/ssh-gss.h
openssh/sshd.c

index 28aeee6515407faba842bd39d0c47fed010bc6df..97fba2dbe1688cafef663baabeba063190dba9ee 100644 (file)
@@ -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
index 010e550ac7dcdd1ce1d596c8b034442a95ecbe8a..19253fe52afe42a893e1bca3d4c429a47e40d0d4 100644 (file)
@@ -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);
+       }
 }
 
 /*
index af183e54660605201fa7586cd65584a548c2e741..f24e133efaccdda2869c81eab2bac5114a8a4e72 100644 (file)
@@ -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
index 7cbf8e2f89b82b7ad18fcbb88a5c1621e9934a68..6fbc09db4d27958200c95f54b5f75dbc4fb0580c 100644 (file)
@@ -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
index bb2f9d6f4fbe09846a79f3658fa3a2c36b4932e7..9369476f66318bba7d401ae9ff3ef1408b22ceb7 100644 (file)
@@ -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);
index 2c9f00e5a47192b47228b9ccb113b45b4eaca563..4ef1d36d283fcf337e4612e0c29c22b9e5a49026 100644 (file)
@@ -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 (file)
index 0000000..3e30504
--- /dev/null
@@ -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 <stdarg.h>
+
+#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 (file)
index 0000000..c94dcd4
--- /dev/null
@@ -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 */
index f0009c80e3a42d3d3aad9c10d8ddbb0420ca57e3..8ff6869a3054e1e9a5db3acffe17194ff924111a 100644 (file)
@@ -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 */
index 12000b1bf5a625add52e281b2c3b878b75aaa4c9..b19bdac91bdfdb4e3e524ec0bb7e5e30002c4a58 100644 (file)
 #include "monitor_wrap.h"
 #include "roaming.h"
 #include "version.h"
+#include "ssh-globus-usage.h"
 
 #ifdef USE_SECURITY_SESSION_API
 #include <Security/AuthSession.h>
@@ -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;
This page took 0.076011 seconds and 5 git commands to generate.