|
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 }; |