components/proftpd/mod_solaris_audit.c
changeset 305 e95b65443448
child 598 398722c80922
child 2251 310a361c2ce7
equal deleted inserted replaced
304:cfebb7b36966 305:e95b65443448
       
     1 /*
       
     2  * ProFTPD - FTP server daemon
       
     3  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; either version 2 of the License, or
       
     8  * (at your option) any later version.
       
     9  *
       
    10  * This program is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    13  * GNU General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License
       
    16  * along with this program; if not, write to the Free Software
       
    17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
       
    18  *
       
    19  * As a special exemption, copyright holders give permission to link
       
    20  * this program with OpenSSL, and distribute the resulting executable,
       
    21  * without including the source code for OpenSSL in the source distribution.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "conf.h"
       
    26 #include <bsm/adt.h>
       
    27 #include <bsm/adt_event.h>
       
    28 #include <security/pam_appl.h>
       
    29 #include <sys/types.h>
       
    30 #include <pwd.h>
       
    31 #include <unistd.h>
       
    32 #include <ucred.h>
       
    33 
       
    34 #ifndef ADT_ftpd
       
    35 #define ADT_ftpd	152
       
    36 #endif
       
    37 
       
    38 #ifndef ADT_ftpd_logout
       
    39 #define ADT_ftpd_logout	153
       
    40 #endif
       
    41 
       
    42 module solaris_audit_module;
       
    43 
       
    44 static adt_session_data_t *asession = NULL;
       
    45 
       
    46 static int auth_retval = PAM_AUTH_ERR;
       
    47 
       
    48 static void audit_autherr_ev(const void *event_data, void *user_data) {
       
    49 
       
    50   switch (*(int *)event_data) {
       
    51   case PR_AUTH_NOPWD:
       
    52     auth_retval = PAM_USER_UNKNOWN;
       
    53     break;
       
    54   case PR_AUTH_AGEPWD:
       
    55     auth_retval = PAM_CRED_EXPIRED;
       
    56     break;
       
    57   case PR_AUTH_DISABLEDPWD:
       
    58     auth_retval = PAM_ACCT_EXPIRED;
       
    59     break;
       
    60   case PR_AUTH_CRED_INSUFF:
       
    61     auth_retval = PAM_CRED_INSUFFICIENT;
       
    62     break;
       
    63   case PR_AUTH_CRED_UNAVAIL:
       
    64     auth_retval = PAM_CRED_UNAVAIL;
       
    65     break;
       
    66   case PR_AUTH_CRED_ERR:
       
    67     auth_retval = PAM_CRED_ERR;
       
    68     break;
       
    69   case PR_AUTH_UNAVAIL:
       
    70     auth_retval = PAM_AUTHINFO_UNAVAIL;
       
    71     break;
       
    72   case PR_AUTH_MAXTRIES:
       
    73     auth_retval = PAM_MAXTRIES;
       
    74     break;
       
    75   case PR_AUTH_INIT_FAIL:
       
    76     auth_retval = PAM_SESSION_ERR;
       
    77     break;
       
    78   case PR_AUTH_NEWTOK:
       
    79     auth_retval = PAM_NEW_AUTHTOK_REQD;
       
    80     break;
       
    81   case PR_AUTH_OPEN_ERR:
       
    82     auth_retval = PAM_OPEN_ERR;
       
    83     break;
       
    84   case PR_AUTH_SYMBOL_ERR:
       
    85     auth_retval = PAM_SYMBOL_ERR;
       
    86     break;
       
    87   case PR_AUTH_SERVICE_ERR:
       
    88     auth_retval = PAM_SERVICE_ERR;
       
    89     break;
       
    90   case PR_AUTH_SYSTEM_ERR:
       
    91     auth_retval = PAM_SYSTEM_ERR;
       
    92     break;
       
    93   case PR_AUTH_BUF_ERR:
       
    94     auth_retval = PAM_BUF_ERR;
       
    95     break;
       
    96   case PR_AUTH_CONV_ERR:
       
    97     auth_retval = PAM_CONV_ERR;
       
    98     break;
       
    99   case PR_AUTH_PERM_DENIED:
       
   100     auth_retval = PAM_PERM_DENIED;
       
   101     break;
       
   102   default: /* PR_AUTH_BADPWD */
       
   103     auth_retval = PAM_AUTH_ERR;
       
   104     break;
       
   105   }
       
   106 
       
   107 }
       
   108 
       
   109 static void audit_failure(pool *p, char *authuser) {
       
   110   adt_event_data_t *event = NULL;
       
   111   const char *how;
       
   112   int saved_errno = 0;
       
   113   struct passwd pwd;
       
   114   char *pwdbuf = NULL;
       
   115   size_t pwdbuf_len;
       
   116   long pwdbuf_len_max;
       
   117   uid_t uid = ADT_NO_ATTRIB;
       
   118   gid_t gid = ADT_NO_ATTRIB;
       
   119 
       
   120   if ((pwdbuf_len_max = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
       
   121     saved_errno = errno;
       
   122     how = "couldn't determine maximum size of password buffer";
       
   123     goto fail;
       
   124   }
       
   125 
       
   126   pwdbuf_len = (size_t)pwdbuf_len_max;
       
   127   pwdbuf = pcalloc(p, pwdbuf_len);
       
   128 
       
   129   if (adt_start_session(&asession, NULL, ADT_USE_PROC_DATA) != 0) {
       
   130     saved_errno = errno;
       
   131     how = "couldn't start adt session";
       
   132     goto fail;
       
   133   }
       
   134 
       
   135   if ((authuser != NULL) && (authuser[0] != NULL) &&
       
   136     (getpwnam_r(authuser, &pwd, pwdbuf, pwdbuf_len) != NULL)) {
       
   137     uid = pwd.pw_uid;
       
   138     gid = pwd.pw_gid;
       
   139   } 
       
   140 
       
   141   if (adt_set_user(asession, uid, gid, uid, gid, NULL, ADT_NEW) != 0) {
       
   142     saved_errno = errno;
       
   143     how = "couldn't set adt user";
       
   144     goto fail;
       
   145   }
       
   146 
       
   147   if ((event = adt_alloc_event(asession, ADT_ftpd)) == NULL) {
       
   148     saved_errno = errno;
       
   149     how = "couldn't allocate adt event";
       
   150     goto fail;
       
   151   }
       
   152 
       
   153   if (adt_put_event(event, ADT_FAILURE, ADT_FAIL_PAM + auth_retval) != 0) {
       
   154     saved_errno = errno;
       
   155     how = "couldn't put adt event";
       
   156     goto fail;
       
   157   }
       
   158 
       
   159   adt_free_event(event);
       
   160   (void) adt_end_session(asession);
       
   161   asession = NULL;
       
   162   return;
       
   163 
       
   164 fail:
       
   165   pr_log_pri(PR_LOG_ERR, "Auditing of login failed: %s (%s)", how,
       
   166     strerror(saved_errno));
       
   167 
       
   168   adt_free_event(event);
       
   169   (void) adt_end_session(asession);
       
   170   asession = NULL;
       
   171 }
       
   172 
       
   173 static void audit_success(void) {
       
   174   adt_event_data_t *event = NULL;
       
   175   const char *how;
       
   176   int saved_errno = 0;
       
   177 
       
   178   if (adt_start_session(&asession, NULL, ADT_USE_PROC_DATA) != 0) {
       
   179     saved_errno = errno;
       
   180     how = "couldn't start adt session";
       
   181     goto fail;
       
   182   }
       
   183 
       
   184   if ((event = adt_alloc_event(asession, ADT_ftpd)) == NULL) {
       
   185     saved_errno = errno;
       
   186     how = "couldn't allocate adt event";
       
   187     goto fail;
       
   188   }
       
   189 
       
   190   if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
       
   191     saved_errno = errno;
       
   192     how = "couldn't put adt event";
       
   193     goto fail;
       
   194   }
       
   195 
       
   196   adt_free_event(event);
       
   197 
       
   198   /* Don't end adt session - leave for when logging out. */
       
   199   return;
       
   200 
       
   201 fail:
       
   202   pr_log_pri(PR_LOG_ERR, "Auditing of login failed: %s (%s)", how,
       
   203     strerror(saved_errno));
       
   204 
       
   205   adt_free_event(event);
       
   206 
       
   207   /* Don't end adt session - leave for when logging out. */
       
   208 
       
   209 }
       
   210 
       
   211 static void audit_logout(void) {
       
   212   adt_event_data_t *event = NULL;
       
   213   const char *how;
       
   214   int saved_errno = 0;
       
   215 
       
   216   /* If audit session was not created during login then leave */
       
   217   if (asession == NULL)
       
   218     return;
       
   219 
       
   220   if ((event = adt_alloc_event(asession, ADT_ftpd_logout)) == NULL) {
       
   221     saved_errno = errno;
       
   222     how = "couldn't allocate adt event";
       
   223     goto fail;
       
   224   }
       
   225 
       
   226   if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
       
   227     saved_errno = errno;
       
   228     how = "couldn't put adt event";
       
   229     goto fail;
       
   230   }
       
   231 
       
   232   adt_free_event(event);
       
   233   (void) adt_end_session(asession);
       
   234   asession = NULL;
       
   235   return;
       
   236 
       
   237 fail:
       
   238   pr_log_pri(PR_LOG_ERR, "Auditing of logout failed: %s (%s)", how,
       
   239     strerror(saved_errno));
       
   240 
       
   241   adt_free_event(event);
       
   242   (void) adt_end_session(asession);
       
   243   asession = NULL;
       
   244 }
       
   245 
       
   246 /* Logout */
       
   247 static void audit_exit_ev(const void *event_data, void *user_data) {
       
   248   audit_logout();
       
   249 }
       
   250 
       
   251 /* Login passed */
       
   252 MODRET solaris_audit_post_pass(cmd_rec *cmd) {
       
   253 
       
   254   audit_success();
       
   255 
       
   256   /* Set handler for logout/timeout */
       
   257   pr_event_register(&solaris_audit_module, "core.exit", audit_exit_ev, NULL);
       
   258 
       
   259   return PR_DECLINED(cmd);
       
   260 }
       
   261 
       
   262 /* Login failed */
       
   263 MODRET solaris_audit_post_fail(cmd_rec *cmd) {
       
   264   char *login_user;
       
   265 
       
   266   login_user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
       
   267 
       
   268   audit_failure(cmd->tmp_pool, login_user);
       
   269   return PR_DECLINED(cmd);
       
   270 }
       
   271 
       
   272 static int audit_sess_init(void) {
       
   273   adt_session_data_t *aht;
       
   274   adt_termid_t *termid;
       
   275   priv_set_t *privset;
       
   276   int rval = -1;					
       
   277 
       
   278   /* add privs for audit init */
       
   279   if ((privset = priv_allocset()) == NULL) {
       
   280     pr_log_pri(PR_LOG_ERR, "Auditing privilege initialization failed");
       
   281     return rval;
       
   282   }
       
   283   (void) getppriv(PRIV_EFFECTIVE, privset);
       
   284   priv_addset(privset, PRIV_SYS_AUDIT);
       
   285   (void) setppriv(PRIV_SET, PRIV_EFFECTIVE, privset);
       
   286 
       
   287   /* basic terminal id setup */
       
   288   if (adt_start_session(&aht, NULL, 0) != 0) {
       
   289     pr_log_pri(PR_LOG_ERR, "pam adt_start_session: %s", strerror(errno));
       
   290     goto out;
       
   291   }
       
   292   if (adt_load_termid(session.c->rfd, &termid) != 0) {
       
   293     pr_log_pri(PR_LOG_ERR, "adt_load_termid: %s", strerror(errno));
       
   294     (void) adt_end_session(aht);
       
   295     goto out;
       
   296   }
       
   297 
       
   298   if (adt_set_user(aht, ADT_NO_AUDIT, ADT_NO_AUDIT, 0, ADT_NO_AUDIT, termid,
       
   299     ADT_SETTID) != 0) {
       
   300     pr_log_pri(PR_LOG_ERR, "adt_set_user: %", strerror(errno));
       
   301     free(termid);
       
   302     (void) adt_end_session(aht);
       
   303     goto out;
       
   304   }
       
   305   free(termid);
       
   306   if (adt_set_proc(aht) != 0) {
       
   307     pr_log_pri(PR_LOG_ERR, "adt_set_proc: %", strerror(errno));
       
   308     (void) adt_end_session(aht);
       
   309     goto out;
       
   310   }
       
   311   (void) adt_end_session(aht);
       
   312 
       
   313   /* Set handler for authentication error */
       
   314   pr_event_register(&solaris_audit_module, "mod_auth.authentication-code",
       
   315     audit_autherr_ev, NULL);
       
   316 
       
   317   rval = 0;
       
   318 
       
   319 out:
       
   320 
       
   321   /* remove unneeded privileges */
       
   322   priv_delset(privset, PRIV_SYS_AUDIT);
       
   323   (void) setppriv(PRIV_SET, PRIV_EFFECTIVE, privset);
       
   324   (void) setpflags(PRIV_AWARE_RESET, 1);
       
   325   priv_freeset(privset);
       
   326 
       
   327   return rval;
       
   328 }
       
   329 
       
   330 #define EVENT_KEY       "event"
       
   331 
       
   332 /* Helper functions and global variables
       
   333  * for the file transfer command handlers.
       
   334  * {
       
   335  */
       
   336 
       
   337 static char src_realpath[PATH_MAX];
       
   338 static char dst_realpath[PATH_MAX];
       
   339 
       
   340 
       
   341 /*
       
   342  * If an error occurs in any of the file transfer handlers,
       
   343  * and the handler wants to return PR_ERROR(cmd), then it is necessary
       
   344  * to send some FTP error message to user. This is in order to prevent
       
   345  * a hang-up of the user's ftp client.
       
   346  *
       
   347  * This function sends the 451 error message to the user.
       
   348  * It is only called in the "pre-" handlers. When a "pre-" handler
       
   349  * returns PR_ERROR(cmd), then the corresponding "post_err-"
       
   350  * handler is also called. Therefore it can happen that an error condition
       
   351  * (such as no memory) can be logged (with the pr_log_pri() routine) twice.
       
   352  * Once in the "pre-" handler, and once in the "post_err-" handler.
       
   353  */
       
   354 static void error_451(void)
       
   355 {
       
   356   pr_response_add_err(R_451,
       
   357     "Requested action aborted: local error in processing.\n");
       
   358 }
       
   359 
       
   360 /*
       
   361  * Allocate resources to process a command outcome.
       
   362  *
       
   363  * All file transfer command handlers need to allocate adt_event_data_t
       
   364  * structure and also make a copy of the command argument.
       
   365  * This function does both. If it can't, it logs an error and returns NULL.
       
   366  * On success, it returns the pointer (event) to the allocated adt_event_data_t
       
   367  * structure.
       
   368  *
       
   369  * If arg2 is not NULL, it makes a copy of the first (and only) command
       
   370  * argument (using the memory pool "pool" from "cmd") and stores it to *arg2.
       
   371  * There must be always exactly one command argument, otherwise it is an error.
       
   372  *
       
   373  * On success, the pointer to the created event structure is stored
       
   374  * into cmd under "notes" variable, so that it is accessible
       
   375  * by the subsequent corresponding "post-" or "post_err-" command handler.
       
   376  */
       
   377 adt_event_data_t* __solaris_audit_pre_arg2(
       
   378     cmd_rec *cmd, const char* description, int event_type, char **arg2) {
       
   379 
       
   380   adt_event_data_t *event = NULL;
       
   381   const char *how = "";
       
   382   char *tmp = NULL;
       
   383 
       
   384   /* The ftp server code will save errno into this variable
       
   385    * in case an error happens, and there is a valid errno for it.
       
   386    */
       
   387   cmd->error_code = ADT_FAILURE;
       
   388 
       
   389   if (cmd->argc != 2) {
       
   390     pr_log_pri(PR_LOG_ERR, "Auditing of %s failed: %s",
       
   391       description, "bad arguments");
       
   392     goto err;
       
   393   }
       
   394 
       
   395   if (arg2 != NULL) {
       
   396     *arg2 = NULL;
       
   397 
       
   398     if ((tmp = pstrdup(cmd->pool, cmd->argv[1])) == NULL) {
       
   399       how = "no memory";
       
   400       pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   401         description, cmd->argv[1], how);
       
   402       goto err;
       
   403     }
       
   404     *arg2 = tmp;
       
   405   }
       
   406 
       
   407   if (cmd->notes == NULL ) {
       
   408     pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   409       description, cmd->argv[1], "API error, notes is NULL");
       
   410     goto err;
       
   411   }
       
   412 
       
   413   if ((event = adt_alloc_event(asession, event_type)) == NULL) {
       
   414     how = "couldn't allocate adt event";
       
   415     pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s(%s)",
       
   416       description, cmd->argv[1], how, strerror(errno));
       
   417     goto err;
       
   418   }
       
   419 
       
   420   if (pr_table_add(cmd->notes, EVENT_KEY, event, sizeof(*event))==-1) {
       
   421     how = "pr_table_add() failed";
       
   422     pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   423       description, cmd->argv[1], how);
       
   424     adt_free_event(event);
       
   425     goto err;
       
   426   }
       
   427   
       
   428   return event;
       
   429 
       
   430 err:
       
   431   return NULL;
       
   432 }
       
   433 
       
   434 /*
       
   435  * This function implements logic that is common to most "post-"
       
   436  * and "post_err-" file transfer command handlers.
       
   437  *
       
   438  * It retrieves the pointer (event) to the adt_event_data_t structure
       
   439  * from "cmd->notes" and logs it. This structure has been created by the
       
   440  * __solaris_audit_pre_arg2() function.
       
   441  * 
       
   442  * Some audit event structures contain an optional *_stat member.
       
   443  * If "fill_attr" is not NULL, it is called to fill in this member,
       
   444  * before the audit event is logged.
       
   445  *
       
   446  * This function always returns PR_DECLINED, even if it failed
       
   447  * to log the audit event. The reason is that it is called in the
       
   448  * "post-" file transfer command handlers, which means that the command
       
   449  * has been already successfully executed by the ftp server.
       
   450  */
       
   451 MODRET __solaris_audit_post(cmd_rec *cmd,
       
   452   const char* description, int exit_status, int __unused,
       
   453   const char* (*fill_event)(cmd_rec *cmd, adt_event_data_t *event))
       
   454 {
       
   455   adt_event_data_t *event = NULL;
       
   456   const char* how = "";
       
   457   const char* msg = NULL;
       
   458   size_t size = 0;
       
   459   int exit_error = cmd->error_code;
       
   460 
       
   461   event = (adt_event_data_t*)pr_table_remove(cmd->notes, EVENT_KEY, &size);
       
   462   if (event == NULL) {
       
   463     how = "event is NULL";
       
   464     pr_log_pri(PR_LOG_ERR, "Auditing of %s failed: %s", description, how);
       
   465     goto out;
       
   466   }
       
   467 
       
   468   if (size != sizeof(*event)) {
       
   469     how = "bad event size";
       
   470     pr_log_pri(PR_LOG_ERR, "Auditing of %s failed: %s", description, how);
       
   471     goto out;
       
   472   }
       
   473 
       
   474   if (fill_event != NULL) {
       
   475     msg = fill_event(cmd, event);
       
   476     if (msg != NULL) {
       
   477       pr_log_pri(PR_LOG_ERR, "Auditing of %s failed: %s", description, msg);
       
   478       goto out;
       
   479     }
       
   480   }
       
   481 
       
   482   /* It can happen, that the ftp command succeeds but only to some degree.
       
   483    * In such case, the exit_error might contain the errno number
       
   484    * of the failure.
       
   485    */
       
   486   if (exit_status == ADT_SUCCESS) {
       
   487     if (exit_error == ADT_FAILURE)
       
   488       exit_error = ADT_SUCCESS;
       
   489   }
       
   490 
       
   491   if (adt_put_event(event, exit_status, exit_error) != 0) {
       
   492     how = "couldn't put adt event";
       
   493     pr_log_pri(PR_LOG_ERR, "Auditing of %s failed: %s (%s)",
       
   494       description, how, strerror(errno));
       
   495   }
       
   496 
       
   497   adt_free_event(event);
       
   498 
       
   499 out:
       
   500   return PR_DECLINED(cmd);
       
   501 }
       
   502 
       
   503 /*
       
   504  * This is a generic function to fill in the given "stat" member
       
   505  * of some audit event structure. The path and the member are specified
       
   506  * by the caller. The pointer to cmd is supplied, because the stat64
       
   507  * structure has to be allocated (the "stat" member is a pointer).
       
   508  *
       
   509  * The function returns NULL on success.
       
   510  * In case of an error, it returns a descriptive message.
       
   511  * This message is used by the caller to log an error.
       
   512  *
       
   513  * For some file transfer commands, the "stat" member is filled in
       
   514  * the "pre-" handler (because the file is expected to exist prior
       
   515  * to the execution of the command). For other file transfer commands,
       
   516  * the "stat" member is filled in the "post-" handler (because
       
   517  * the file is expected _not_ to exist prior to the execution of the command,
       
   518  * but to exist after the command execution).
       
   519  */
       
   520 static const char* __fill_attr
       
   521 (
       
   522   cmd_rec *cmd, const char* path, adt_stat_t **ret)
       
   523 {
       
   524   struct stat64 *ptr;
       
   525   int err;
       
   526 
       
   527   if (ret == NULL)
       
   528     return "NULL pointer";
       
   529 
       
   530   *ret = NULL;
       
   531 
       
   532   ptr = palloc(cmd->pool, sizeof(*ptr));
       
   533   if (ptr == NULL)
       
   534     return "no memory";
       
   535 
       
   536   err = stat64(path, ptr);
       
   537   if (err == -1)
       
   538     return "stat64() failed";
       
   539 
       
   540   *ret = ptr;
       
   541   return NULL;
       
   542 }
       
   543 /* } */
       
   544 
       
   545 
       
   546 /* Delete file. { */
       
   547 static const char* dele_fill_attr(cmd_rec *cmd, adt_event_data_t *event) {
       
   548   return __fill_attr(
       
   549     cmd, event->adt_ft_remove.f_path, &(event->adt_ft_remove.f_attr)
       
   550   );
       
   551 }
       
   552 
       
   553 MODRET solaris_audit_pre_dele(cmd_rec *cmd) {
       
   554   adt_event_data_t *event = NULL;
       
   555   char* ptr = NULL;
       
   556   char* rp = NULL;
       
   557 
       
   558   event = __solaris_audit_pre_arg2(cmd, "remove", ADT_ft_remove, &ptr);
       
   559   if (event == NULL) {
       
   560     error_451();
       
   561     return PR_ERROR(cmd);
       
   562   }
       
   563 
       
   564   rp = realpath(ptr, src_realpath);
       
   565   if (rp == NULL) {
       
   566     if (errno != ENOENT) {
       
   567       pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   568         "remove", ptr, "realpath() failed");
       
   569       cmd->error_code = errno;
       
   570       error_451();
       
   571       return PR_ERROR(cmd);
       
   572     }
       
   573     /* If rp is NULL and errno is ENOENT, it means that 
       
   574      * the file to be deleted does not exist. In this case,
       
   575      * the post_dele_err callback will be called to log this.
       
   576      */
       
   577   }
       
   578 
       
   579   if (rp != NULL)
       
   580     ptr = rp;    
       
   581 
       
   582   event->adt_ft_remove.f_path = ptr;
       
   583   (void) dele_fill_attr(cmd, event);
       
   584 
       
   585   return PR_DECLINED(cmd);
       
   586 }
       
   587 
       
   588 MODRET solaris_audit_post_dele(cmd_rec *cmd) {
       
   589   return __solaris_audit_post(
       
   590     cmd, "remove", ADT_SUCCESS, ADT_SUCCESS, NULL);
       
   591 }
       
   592 
       
   593 MODRET solaris_audit_post_dele_err(cmd_rec *cmd) {
       
   594   return __solaris_audit_post(cmd, "remove", ADT_FAILURE, ADT_FAILURE, NULL);
       
   595 }
       
   596 /* } */
       
   597 
       
   598 
       
   599 /* Make directory. { */
       
   600 MODRET solaris_audit_pre_mkd(cmd_rec *cmd) {
       
   601   adt_event_data_t *event = NULL;
       
   602   char* ptr = NULL;
       
   603 
       
   604   event = __solaris_audit_pre_arg2(cmd, "mkdir", ADT_ft_mkdir, &ptr);
       
   605   if (event == NULL) {
       
   606     error_451();
       
   607     return PR_ERROR(cmd);
       
   608   }
       
   609 
       
   610   event->adt_ft_mkdir.d_path = ptr;
       
   611   event->adt_ft_mkdir.d_attr = NULL;
       
   612 
       
   613   /* Value 0777 is hardcoded in the ftp server. */
       
   614   event->adt_ft_mkdir.arg = 0777;
       
   615   event->adt_ft_mkdir.arg_id = 2;
       
   616   event->adt_ft_mkdir.arg_desc = "mode";
       
   617 
       
   618   return PR_DECLINED(cmd);
       
   619 }
       
   620 
       
   621 static const char* mkd_fill_event(cmd_rec *cmd, adt_event_data_t *event) {
       
   622   char *rp = NULL;
       
   623 
       
   624   rp = realpath(event->adt_ft_mkdir.d_path, src_realpath);
       
   625   if (rp == NULL) {
       
   626     cmd->error_code = errno;
       
   627     return "realpath() failed";
       
   628   }
       
   629 
       
   630   event->adt_ft_mkdir.d_path = rp;
       
   631   return __fill_attr(
       
   632     cmd, event->adt_ft_mkdir.d_path, &(event->adt_ft_mkdir.d_attr)
       
   633   );
       
   634 }
       
   635 
       
   636 static const char* mkd_fill_event_err(cmd_rec *cmd, adt_event_data_t *event) {
       
   637   char *rp = NULL;
       
   638 
       
   639   rp = realpath(event->adt_ft_mkdir.d_path, src_realpath);
       
   640   if (rp != NULL) {
       
   641     event->adt_ft_mkdir.d_path = rp;
       
   642     (void) __fill_attr(
       
   643       cmd, event->adt_ft_mkdir.d_path, &(event->adt_ft_mkdir.d_attr)); 
       
   644   }
       
   645 
       
   646   return NULL;
       
   647 }
       
   648 
       
   649 MODRET solaris_audit_post_mkd(cmd_rec *cmd) {
       
   650   return __solaris_audit_post(
       
   651     cmd, "mkdir", ADT_SUCCESS, ADT_SUCCESS, mkd_fill_event);
       
   652 }
       
   653 
       
   654 MODRET solaris_audit_post_mkd_err(cmd_rec *cmd) {
       
   655   return __solaris_audit_post(
       
   656     cmd, "mkdir", ADT_FAILURE, ADT_FAILURE, mkd_fill_event_err);
       
   657 }
       
   658 /* } */
       
   659 
       
   660 /* Remove directory. { */
       
   661 static const char* rmd_fill_attr(cmd_rec *cmd, adt_event_data_t *event) {
       
   662   return __fill_attr(
       
   663     cmd, event->adt_ft_rmdir.f_path, &(event->adt_ft_rmdir.f_attr)
       
   664   );
       
   665 }
       
   666 
       
   667 MODRET solaris_audit_pre_rmd(cmd_rec *cmd) {
       
   668   adt_event_data_t *event = NULL;
       
   669   char* ptr = NULL;
       
   670   char* rp = NULL;
       
   671  
       
   672   event = __solaris_audit_pre_arg2(cmd, "rmdir", ADT_ft_rmdir, &ptr);
       
   673   if (event == NULL) {
       
   674     error_451();
       
   675     return PR_ERROR(cmd);
       
   676   }
       
   677 
       
   678   rp = realpath(ptr, src_realpath);
       
   679   if (rp == NULL) {
       
   680     if (errno != ENOENT) {
       
   681       cmd->error_code = errno;
       
   682       pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   683         "rmdir", ptr, "realpath() failed");
       
   684       error_451();
       
   685       return PR_ERROR(cmd);
       
   686     }
       
   687   }
       
   688 
       
   689   if (rp != NULL)
       
   690     ptr = rp;
       
   691 
       
   692   event->adt_ft_rmdir.f_path = ptr;
       
   693   (void) rmd_fill_attr(cmd, event);
       
   694 
       
   695   return PR_DECLINED(cmd);
       
   696 }
       
   697 
       
   698 MODRET solaris_audit_post_rmd(cmd_rec *cmd) {
       
   699   return __solaris_audit_post(cmd, "rmdir", ADT_SUCCESS, ADT_SUCCESS, NULL);
       
   700 }
       
   701 
       
   702 MODRET solaris_audit_post_rmd_err(cmd_rec *cmd) {
       
   703   return __solaris_audit_post(cmd, "rmdir", ADT_FAILURE, ADT_FAILURE, NULL);
       
   704 }
       
   705 /* } */
       
   706 
       
   707 /* Get modification time and date. { */
       
   708 MODRET solaris_audit_pre_mdtm(cmd_rec *cmd) {
       
   709   adt_event_data_t *event = NULL;
       
   710   char* ptr = NULL;
       
   711   char* rp = NULL;
       
   712   
       
   713   event = __solaris_audit_pre_arg2(cmd, "utimes", ADT_ft_utimes, &ptr);
       
   714   if (event == NULL) {
       
   715     error_451();
       
   716     return PR_ERROR(cmd);
       
   717   }
       
   718 
       
   719   rp = realpath(ptr, src_realpath);
       
   720   if (rp == NULL) {
       
   721     if (errno != ENOENT) {
       
   722       cmd->error_code = errno;
       
   723       pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   724         "utimes", ptr, "realpath() failed");
       
   725       error_451();
       
   726       return PR_ERROR(cmd);
       
   727     }
       
   728   }
       
   729 
       
   730   if (rp != NULL)
       
   731     ptr = rp;
       
   732 
       
   733   event->adt_ft_utimes.f_path = ptr;
       
   734   event->adt_ft_utimes.f_attr = NULL;
       
   735 
       
   736   return PR_DECLINED(cmd);
       
   737 }
       
   738 
       
   739 static const char* mdtm_fill_attr(cmd_rec *cmd, adt_event_data_t *event) {
       
   740   return __fill_attr(
       
   741     cmd, event->adt_ft_utimes.f_path, &(event->adt_ft_utimes.f_attr)
       
   742   );
       
   743 }
       
   744 
       
   745 MODRET solaris_audit_post_mdtm(cmd_rec *cmd) {
       
   746   return __solaris_audit_post(
       
   747     cmd, "utimes", ADT_SUCCESS, ADT_SUCCESS, mdtm_fill_attr);
       
   748 }
       
   749 
       
   750 MODRET solaris_audit_post_mdtm_err(cmd_rec *cmd) {
       
   751   return __solaris_audit_post(cmd, "utimes", ADT_FAILURE, ADT_FAILURE, NULL);
       
   752 }
       
   753 /* } */
       
   754 
       
   755 /* Upload file. { */
       
   756 MODRET solaris_audit_pre_put(cmd_rec *cmd) {
       
   757   adt_event_data_t *event = NULL;
       
   758   char* ptr = NULL;
       
   759   
       
   760   event = __solaris_audit_pre_arg2(cmd, "put", ADT_ft_put, &ptr);
       
   761   if (event == NULL) {
       
   762     error_451();
       
   763     return PR_ERROR(cmd);
       
   764   }
       
   765 
       
   766   event->adt_ft_put.f_path = ptr;
       
   767   event->adt_ft_put.f_attr = NULL;
       
   768 
       
   769   return PR_DECLINED(cmd);
       
   770 }
       
   771 
       
   772 static const char* put_fill_event(cmd_rec *cmd, adt_event_data_t *event) {
       
   773   char *rp = NULL;
       
   774 
       
   775   rp = realpath(event->adt_ft_put.f_path, src_realpath);
       
   776   if (rp == NULL) {
       
   777     cmd->error_code = errno;
       
   778     return "realpath() failed";
       
   779   }
       
   780 
       
   781   event->adt_ft_put.f_path = rp;
       
   782   return __fill_attr(
       
   783     cmd, event->adt_ft_put.f_path, &(event->adt_ft_put.f_attr)
       
   784   );
       
   785 }
       
   786 
       
   787 MODRET solaris_audit_post_put(cmd_rec *cmd) {
       
   788   return __solaris_audit_post(
       
   789     cmd, "put", ADT_SUCCESS, ADT_SUCCESS, put_fill_event);
       
   790 }
       
   791 
       
   792 MODRET solaris_audit_post_put_err(cmd_rec *cmd) {
       
   793   return __solaris_audit_post(cmd, "put", ADT_FAILURE, ADT_FAILURE, NULL);
       
   794 }
       
   795 /* } */
       
   796 
       
   797 /* Download file. { */
       
   798 MODRET solaris_audit_pre_get(cmd_rec *cmd) {
       
   799   adt_event_data_t *event = NULL;
       
   800   char* ptr = NULL;
       
   801   char* rp = NULL;
       
   802   
       
   803   event = __solaris_audit_pre_arg2(cmd, "get", ADT_ft_get, &ptr);
       
   804   if (event == NULL) {
       
   805     error_451();
       
   806     return PR_ERROR(cmd);
       
   807   }
       
   808 
       
   809   rp = realpath(ptr, src_realpath);
       
   810   if (rp == NULL) {
       
   811     if (errno != ENOENT) {
       
   812       cmd->error_code = errno;
       
   813       pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   814         "get", ptr, "realpath() failed");
       
   815       error_451();
       
   816       return PR_ERROR(cmd);
       
   817     }
       
   818   }
       
   819 
       
   820   if (rp != NULL)
       
   821     ptr = rp;
       
   822 
       
   823   event->adt_ft_get.f_path = ptr;
       
   824   event->adt_ft_get.f_attr = NULL;
       
   825 
       
   826   return PR_DECLINED(cmd);
       
   827 }
       
   828 
       
   829 static const char* get_fill_attr(cmd_rec *cmd, adt_event_data_t *event) {
       
   830   return __fill_attr(
       
   831     cmd, event->adt_ft_get.f_path, &(event->adt_ft_get.f_attr)
       
   832   );
       
   833 }
       
   834 
       
   835 MODRET solaris_audit_post_get(cmd_rec *cmd) {
       
   836   return __solaris_audit_post(
       
   837     cmd, "get", ADT_SUCCESS, ADT_SUCCESS, get_fill_attr);
       
   838 }
       
   839 
       
   840 MODRET solaris_audit_post_get_err(cmd_rec *cmd) {
       
   841   return __solaris_audit_post(cmd, "get", ADT_FAILURE, ADT_FAILURE, NULL);
       
   842 }
       
   843 /* } */
       
   844 
       
   845 /* Rename file. { */
       
   846 /*
       
   847  * The rename file implementation uses malloc()/free(),
       
   848  * which the ProFTP module interface prohibits. I do not see another way.
       
   849  * 
       
   850  * Any memory allocation method provided by the ProFTP API uses a memory pool.
       
   851  * To avoid malloc()/free() a persistent memory pool is needed.
       
   852  */
       
   853 
       
   854 /*
       
   855  * To successfully log the rename audit event, a cooperation
       
   856  * of RNFR and RNTO command handlers is necessary.
       
   857  * The RNFR command specifies the source file name,
       
   858  * and the RNTO command specifies the destination file name.
       
   859  * 
       
   860  * The RNFR command handlers save the source file in the "src_path"
       
   861  * variable, so that it is available to the RNTO command handler,
       
   862  * which logs the audit event.
       
   863  */
       
   864 static char* src_path = NULL;
       
   865 
       
   866 /* RNFR. { */
       
   867 static void __solaris_audit_rnfr_err(cmd_rec *cmd)
       
   868 {
       
   869   adt_event_data_t *event = NULL;
       
   870 
       
   871   if (src_path == NULL)
       
   872     return;
       
   873 
       
   874   event = __solaris_audit_pre_arg2(cmd, "RNFR", ADT_ft_rename, NULL);
       
   875   if (event == NULL) {
       
   876     error_451();
       
   877     goto out;
       
   878   }
       
   879 
       
   880   event->adt_ft_rename.src_path = src_path;
       
   881   event->adt_ft_rename.src_attr = NULL;
       
   882   event->adt_ft_rename.dst_path = NULL;
       
   883 
       
   884   (void) __solaris_audit_post(cmd, "RNFR", ADT_FAILURE, ADT_FAILURE, NULL);
       
   885 
       
   886 out:
       
   887   free(src_path);
       
   888   src_path = NULL;
       
   889 }
       
   890 
       
   891 MODRET solaris_audit_pre_rnfr(cmd_rec *cmd) {
       
   892   adt_event_data_t *event = NULL;
       
   893   char* ptr = NULL;
       
   894 
       
   895   /*
       
   896    * If src_path is not NULL, it means that this RNFR command immediatelly
       
   897    * follows a successfull RNFR command not terminated with a RNTO command.
       
   898    * In such case, log an audit error for this unterminated RNFR command,
       
   899    * and then continue normally.
       
   900    *
       
   901    * A correctly working ftp client can not cause this situation to happen.
       
   902    * But this situation can be created, for instance, by manually sending
       
   903    * commands to the ftp server with a telnet client.
       
   904    */
       
   905   if (src_path != NULL)
       
   906     __solaris_audit_rnfr_err(cmd);
       
   907 
       
   908   /*
       
   909    * Prepare the audit event structure and remember the new src_path.
       
   910    * This audit event structure will be used, if the RNFR command fails.
       
   911    * It will be unused, if it succeeds.
       
   912    */
       
   913   event = __solaris_audit_pre_arg2(cmd, "get", ADT_ft_rename, &ptr);
       
   914   if (event == NULL)
       
   915     goto err;
       
   916 
       
   917   event->adt_ft_rename.src_path = ptr;
       
   918   event->adt_ft_rename.src_attr = NULL;
       
   919   event->adt_ft_rename.dst_path = "";
       
   920 
       
   921   src_path = strdup(cmd->argv[1]);
       
   922   if (src_path == NULL) {
       
   923     pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   924       "RNFR", ptr, "no memory");
       
   925     goto err;
       
   926   }
       
   927 
       
   928   return PR_DECLINED(cmd);
       
   929 err:
       
   930   return PR_ERROR(cmd);
       
   931 }
       
   932 
       
   933 /*
       
   934  * On success, the RNFR command handlers do not log any audit event.
       
   935  * A success means that a rename command is in progress and that
       
   936  * the immediatelly following command is to be RNTO. 
       
   937  */
       
   938 MODRET solaris_audit_post_rnfr(cmd_rec *cmd) {
       
   939 
       
   940   char *ptr;
       
   941 
       
   942   ptr = realpath(src_path, src_realpath);
       
   943   if (ptr == NULL) {
       
   944     pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s) failed: %s",
       
   945       "RNFR", src_path, "realpath() failed");
       
   946     error_451();
       
   947     return PR_ERROR(cmd);
       
   948   }
       
   949 
       
   950   /*
       
   951    * The argument to RNFR command is saved in src_path.
       
   952    * It will be used in the subsequent RNTO command, or RNFR command.
       
   953    */
       
   954   return PR_DECLINED(cmd);
       
   955 }
       
   956 
       
   957 /* It can happen, that RNFR command fails, but the source path exists.
       
   958  * Therefore make an attempt to resolve its realpath before doing
       
   959  * the audit log.
       
   960  *
       
   961  * Even if the realpath() call fails, the src_path contents are still
       
   962  * copied to src_realpath buffer. This makes them available to the RNTO
       
   963  * command handlers.
       
   964  */
       
   965 static const char* rnfr_err_fill_event(cmd_rec *cmd, adt_event_data_t *event) {
       
   966   char *ptr = NULL;
       
   967 
       
   968   if (src_path != NULL) {
       
   969     ptr = realpath(src_path, src_realpath);
       
   970     if (ptr != NULL)
       
   971       event->adt_ft_rename.src_path = ptr;
       
   972   }
       
   973 
       
   974   return NULL;
       
   975 }
       
   976 
       
   977 /*
       
   978  * On error, an audit event is logged, specifying that a rename
       
   979  * command failed. The destination path in the audit event structure
       
   980  * is empty, simply because the corresponding RNTO command did not yet
       
   981  * happen, and it is not suppossed to happen.
       
   982  */
       
   983 MODRET solaris_audit_post_rnfr_err(cmd_rec *cmd) {
       
   984   MODRET ret;
       
   985 
       
   986   ret = __solaris_audit_post(cmd, "RNFR", ADT_FAILURE, ADT_FAILURE,
       
   987     rnfr_err_fill_event);
       
   988 
       
   989   free(src_path);
       
   990   src_path = NULL;
       
   991 
       
   992   return ret;
       
   993 }
       
   994 /* } RNFR. */
       
   995 
       
   996 /* RNTO. { */
       
   997 static const char* rnto_fill_attr(cmd_rec *cmd, adt_event_data_t *event) {
       
   998   return __fill_attr(
       
   999     cmd, event->adt_ft_rename.src_path, &(event->adt_ft_rename.src_attr)
       
  1000   );
       
  1001 }
       
  1002 
       
  1003 MODRET solaris_audit_pre_rnto(cmd_rec *cmd) {
       
  1004   adt_event_data_t *event = NULL;
       
  1005   const char* msg = NULL;
       
  1006   char* ptr = NULL;
       
  1007 
       
  1008   event = __solaris_audit_pre_arg2(cmd, "get", ADT_ft_rename, &ptr);
       
  1009   if (event == NULL)
       
  1010     goto err;
       
  1011 
       
  1012   /*
       
  1013    * If src_path is NULL, this means that there is no previous
       
  1014    * successfull RNFR command. The ftp server should know about this
       
  1015    * and terminate this RNTO command with an error (call the error callback).
       
  1016    */
       
  1017   event->adt_ft_rename.src_path = (src_path)?src_path:"";
       
  1018   event->adt_ft_rename.dst_path = ptr;
       
  1019 
       
  1020   /*
       
  1021    * If the code executes here, it means that there is a successfully finished
       
  1022    * RNFR command immediatelly before us, which means that the src_path exists,
       
  1023    * and it should be therefore possible to get its status.
       
  1024    */
       
  1025   msg = rnto_fill_attr(cmd, event);  
       
  1026   if (msg != NULL) {
       
  1027     pr_log_pri(PR_LOG_ERR, "Auditing of %s(%s,%s) failed: %s",
       
  1028       "RNTO", event->adt_ft_rename.src_path, ptr, msg);
       
  1029     goto err;
       
  1030   }
       
  1031 
       
  1032   return PR_DECLINED(cmd);
       
  1033 
       
  1034 err:
       
  1035   error_451();
       
  1036   return PR_ERROR(cmd);
       
  1037 }
       
  1038 
       
  1039 static const char* rnto_fill_event(cmd_rec *cmd, adt_event_data_t *event) {
       
  1040   char *ptr;
       
  1041 
       
  1042   ptr = realpath(event->adt_ft_rename.dst_path, dst_realpath);
       
  1043   if (ptr == NULL) {
       
  1044     return "realpath() failed";
       
  1045   }
       
  1046 
       
  1047   event->adt_ft_rename.src_path = src_realpath;
       
  1048   event->adt_ft_rename.dst_path = dst_realpath;
       
  1049 
       
  1050   return NULL;
       
  1051 }
       
  1052 
       
  1053 MODRET solaris_audit_post_rnto(cmd_rec *cmd) {
       
  1054    MODRET retval;
       
  1055 
       
  1056   /* NULL means that there is no preceeding successfull RNFR command. */
       
  1057   if (src_path == NULL)
       
  1058     return PR_ERROR(cmd);
       
  1059 
       
  1060   retval = __solaris_audit_post(cmd, "RNTO", ADT_SUCCESS, ADT_SUCCESS,
       
  1061     rnto_fill_event);
       
  1062   
       
  1063   free(src_path);
       
  1064   src_path = NULL;
       
  1065 
       
  1066   return retval;
       
  1067 }
       
  1068 
       
  1069 /* It can happen, that RNTO command fails, but the destination path exists.
       
  1070  * Therefore make an attempt to resolve its realpath before doing
       
  1071  * the audit log.
       
  1072  */
       
  1073 static const char* rnto_err_fill_event(cmd_rec *cmd, adt_event_data_t *event) {
       
  1074 
       
  1075   (void) realpath(event->adt_ft_rename.dst_path, dst_realpath);
       
  1076   event->adt_ft_rename.src_path = src_realpath;
       
  1077   event->adt_ft_rename.dst_path = dst_realpath;
       
  1078 
       
  1079   return NULL;
       
  1080 }
       
  1081 
       
  1082 MODRET solaris_audit_post_rnto_err(cmd_rec *cmd) {
       
  1083   MODRET retval;
       
  1084   retval = __solaris_audit_post(cmd, "RNTO", ADT_FAILURE, ADT_FAILURE,
       
  1085     rnto_err_fill_event);
       
  1086   if (src_path != NULL) {
       
  1087     free(src_path);
       
  1088     src_path = NULL;
       
  1089   }
       
  1090   return retval;
       
  1091 }
       
  1092 /* } RNTO. */
       
  1093 
       
  1094 static cmdtable solaris_audit_commands[] = {
       
  1095     /* Login, logout. */
       
  1096     { POST_CMD, C_PASS, G_NONE, solaris_audit_post_pass, FALSE, FALSE },
       
  1097     { POST_CMD_ERR, C_PASS, G_NONE, solaris_audit_post_fail, FALSE, FALSE },
       
  1098 
       
  1099     /* Delete file. */
       
  1100     { PRE_CMD, C_DELE, G_NONE, solaris_audit_pre_dele, FALSE, FALSE },
       
  1101     { POST_CMD, C_DELE, G_NONE, solaris_audit_post_dele, FALSE, FALSE },
       
  1102     { POST_CMD_ERR, C_DELE, G_NONE, solaris_audit_post_dele_err,
       
  1103         FALSE, FALSE },
       
  1104 
       
  1105     /* Make directory. */
       
  1106     { PRE_CMD, C_MKD, G_NONE, solaris_audit_pre_mkd, FALSE, FALSE },
       
  1107     { POST_CMD, C_MKD, G_NONE, solaris_audit_post_mkd, FALSE, FALSE },
       
  1108     { POST_CMD_ERR, C_MKD, G_NONE, solaris_audit_post_mkd_err,
       
  1109         FALSE, FALSE },
       
  1110 
       
  1111     /* Remove directory. */
       
  1112     { PRE_CMD, C_RMD, G_NONE, solaris_audit_pre_rmd, FALSE, FALSE },
       
  1113     { POST_CMD, C_RMD, G_NONE, solaris_audit_post_rmd, FALSE, FALSE },
       
  1114     { POST_CMD_ERR, C_RMD, G_NONE, solaris_audit_post_rmd_err,
       
  1115         FALSE, FALSE },
       
  1116 
       
  1117     { PRE_CMD, C_XRMD, G_NONE, solaris_audit_pre_rmd, FALSE, FALSE },
       
  1118     { POST_CMD, C_XRMD, G_NONE, solaris_audit_post_rmd, FALSE, FALSE },
       
  1119     { POST_CMD_ERR, C_XRMD, G_NONE, solaris_audit_post_rmd_err,
       
  1120         FALSE, FALSE },
       
  1121 
       
  1122     /* Get modification time. */
       
  1123     { PRE_CMD, C_MDTM, G_NONE, solaris_audit_pre_mdtm, FALSE, FALSE },
       
  1124     { POST_CMD, C_MDTM, G_NONE, solaris_audit_post_mdtm, FALSE, FALSE },
       
  1125     { POST_CMD_ERR, C_MDTM, G_NONE, solaris_audit_post_mdtm_err,
       
  1126         FALSE, FALSE },
       
  1127 
       
  1128     /* Upload file. */
       
  1129     { PRE_CMD, C_STOR, G_WRITE, solaris_audit_pre_put, FALSE, FALSE },
       
  1130     { POST_CMD, C_STOR, G_WRITE, solaris_audit_post_put, FALSE, FALSE },
       
  1131     { POST_CMD_ERR, C_STOR, G_WRITE, solaris_audit_post_put_err,
       
  1132         FALSE, FALSE },
       
  1133 
       
  1134     { PRE_CMD, C_STOU, G_WRITE, solaris_audit_pre_put, FALSE, FALSE },
       
  1135     { POST_CMD, C_STOU, G_WRITE, solaris_audit_post_put, FALSE, FALSE },
       
  1136     { POST_CMD_ERR, C_STOU, G_WRITE, solaris_audit_post_put_err,
       
  1137         FALSE, FALSE },
       
  1138 
       
  1139     { PRE_CMD, C_APPE, G_WRITE, solaris_audit_pre_put, FALSE, FALSE },
       
  1140     { POST_CMD, C_APPE, G_WRITE, solaris_audit_post_put, FALSE, FALSE },
       
  1141     { POST_CMD_ERR, C_APPE, G_WRITE, solaris_audit_post_put_err,
       
  1142         FALSE, FALSE },
       
  1143 
       
  1144     /* Download file. */
       
  1145     { PRE_CMD, C_RETR, G_READ, solaris_audit_pre_get, FALSE, FALSE },
       
  1146     { POST_CMD, C_RETR, G_READ, solaris_audit_post_get, FALSE, FALSE },
       
  1147     { POST_CMD_ERR, C_RETR, G_READ, solaris_audit_post_get_err,
       
  1148         FALSE, FALSE },
       
  1149 
       
  1150     /* Rename file. */
       
  1151     { PRE_CMD, C_RNFR, G_NONE, solaris_audit_pre_rnfr, FALSE, FALSE },
       
  1152     { POST_CMD, C_RNFR, G_NONE, solaris_audit_post_rnfr, FALSE, FALSE },
       
  1153     { POST_CMD_ERR, C_RNFR, G_NONE, solaris_audit_post_rnfr_err,
       
  1154         FALSE, FALSE },
       
  1155 
       
  1156     { PRE_CMD, C_RNTO, G_NONE, solaris_audit_pre_rnto, FALSE, FALSE },
       
  1157     { POST_CMD, C_RNTO, G_NONE, solaris_audit_post_rnto, FALSE, FALSE },
       
  1158     { POST_CMD_ERR, C_RNTO, G_NONE, solaris_audit_post_rnto_err,
       
  1159         FALSE, FALSE },
       
  1160 
       
  1161 	{ 0, NULL }
       
  1162 };
       
  1163 
       
  1164 module solaris_audit_module = {
       
  1165 	NULL, NULL,		/* Always NULL */
       
  1166 	0x20,			/* API Version 2.0 */
       
  1167 	"solaris_audit",
       
  1168 	NULL,			/* configuration table */
       
  1169 	solaris_audit_commands,	/* command table is for local use only */
       
  1170 	NULL,			/* No authentication handlers */
       
  1171 	NULL,			/* No initialization function */
       
  1172 	audit_sess_init		/* Post-fork "child mode" init */
       
  1173 };