Whamcloud - gitweb
- small fixes after landing
[fs/lustre-release.git] / lustre / smfs / audit.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/smfs/audit_mds.c
5  *  Lustre filesystem audit part for MDS
6  *
7  *  Copyright (C) 2004 Cluster File Systems, Inc.
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24 #ifndef EXPORT_SYMTAB
25 # define EXPORT_SYMTAB
26 #endif
27
28 #define DEBUG_SUBSYSTEM S_SM
29
30 #include <linux/kmod.h>
31 #include <linux/init.h>
32 #include <linux/fs.h>
33 #include <linux/slab.h>
34 #include <linux/obd_class.h>
35 #include <linux/obd_support.h>
36 #include <linux/lustre_lib.h>
37 #include <linux/lustre_idl.h>
38 #include <linux/lustre_fsfilt.h>
39 #include <linux/lustre_smfs.h>
40 #include <linux/lustre_audit.h>
41 #include <linux/lustre_log.h>
42 #include "smfs_internal.h"
43
44 static audit_op hook2audit(hook_op hook)
45 {
46         audit_op opcode = AUDIT_NONE;
47
48         switch (hook) 
49         {
50                 case HOOK_CREATE:
51                 case HOOK_SYMLINK:
52                 case HOOK_MKDIR:
53                 case HOOK_MKNOD:
54                         return AUDIT_CREATE;
55                         
56                 case HOOK_LINK:
57                         return AUDIT_LINK;
58                                                 
59                 case HOOK_RMDIR:
60                 case HOOK_UNLINK:
61                         return AUDIT_UNLINK;
62                         
63                 case HOOK_READLINK:
64                         return AUDIT_READLINK;
65                         
66                 case HOOK_RENAME:
67                         return AUDIT_RENAME;
68                         
69                 case HOOK_SETATTR:
70                 case HOOK_F_SETATTR:
71                         return AUDIT_SETATTR;
72                         
73                 case HOOK_SI_WRITE:
74                         return AUDIT_WRITE;
75                         
76                 case HOOK_SI_READ:
77                         return AUDIT_READ;
78
79                 case HOOK_READDIR:
80                         return AUDIT_READDIR;
81
82                 default:
83                         return AUDIT_NONE;
84         }
85         
86         return opcode;
87 }
88
89 struct inode * get_inode_from_hook(hook_op hook, void * msg) 
90 {
91         struct inode * inode;
92         
93         switch (hook)
94         {
95                 case HOOK_LINK:
96                 {
97                         struct hook_link_msg * m = msg;
98                         inode = m->dentry->d_inode;
99                         break;
100                 }
101                 case HOOK_UNLINK:
102                 case HOOK_RMDIR:
103                 {
104                         struct hook_unlink_msg * m = msg;
105                         inode = m->dentry->d_inode;
106                         break;
107                 }
108                 case HOOK_READLINK:
109                 {
110                         struct hook_symlink_msg * m = msg;
111                         inode = m->dentry->d_inode;
112                         break;
113                 }        
114                 case HOOK_RENAME:
115                 {
116                         struct hook_rename_msg * m = msg;
117                         inode = m->dentry->d_inode;
118                         break;
119                 }        
120                 default:
121                         inode = NULL;
122         }
123
124         return inode;
125 }
126
127 int smfs_get_audit(struct super_block * sb, struct inode * parent,
128                    struct inode * inode,  __u64 * mask)
129 {
130         struct smfs_super_info * smb = S2SMI(sb);
131         struct fsfilt_operations *fsfilt = smb->sm_fsfilt;
132         int rc;
133         struct audit_priv * priv = NULL;
134         
135         ENTRY;
136         
137         if (!SMFS_IS(smb->plg_flags, SMFS_PLG_AUDIT))
138                 RETURN(-EINVAL);
139         
140         priv = smfs_get_plg_priv(S2SMI(sb), SMFS_PLG_AUDIT);
141               
142         //omit __iopen__ dir
143         if (parent->i_ino == SMFS_IOPEN_INO)
144                 RETURN(-ENOENT);
145         
146         if (!priv)
147                 RETURN(-ENOENT);
148         
149         if (IS_AUDIT(priv->a_mask)) {
150                 (*mask) = priv->a_mask;
151                 RETURN(0);
152         }
153         //get inode audit EA
154         rc = fsfilt->fs_get_xattr(parent, AUDIT_ATTR_EA,
155                                   mask, sizeof(*mask));
156         if (rc <= 0)
157                 RETURN(-ENODATA);
158         
159         //check if parent has audit
160         if (IS_AUDIT(*mask))
161                 RETURN(0);
162         
163         if (!inode)
164                 RETURN(-ENOENT);
165         
166         rc = fsfilt->fs_get_xattr(inode, AUDIT_ATTR_EA,
167                                   mask, sizeof(*mask));
168         if (rc <= 0)
169                 RETURN(-ENODATA);
170         
171         if (IS_AUDIT(*mask))
172                 RETURN(0);
173
174         RETURN(-ENODATA);
175 }
176
177 int smfs_audit_check(struct inode * parent, hook_op hook, int ret,
178                      struct audit_priv * priv, void * msg)
179 {
180         audit_op code;
181         __u64 mask = 0;
182         int rc = 0;
183         
184         ENTRY;
185
186         if (hook == HOOK_SPECIAL) { 
187                 struct audit_info * info = msg;
188                 code = info->m.code;
189         }
190         else
191                 code = hook2audit(hook);
192
193         rc = smfs_get_audit(parent->i_sb, parent,
194                             get_inode_from_hook(hook, msg),
195                             &mask);
196         if (rc < 0)
197                 RETURN(0);
198         //should only failures be audited?
199         if (!ret && IS_AUDIT_OP(mask, AUDIT_FAIL))
200                 RETURN(0); 
201
202         //check audit mask
203         RETURN(IS_AUDIT_OP(mask, code));
204 }
205
206 static int smfs_set_fs_audit (struct super_block * sb, __u64 *mask)
207 {
208         struct smfs_super_info * smb = S2SMI(sb);
209         struct fsfilt_operations * fsfilt = smb->sm_fsfilt;
210         int rc = 0;
211         loff_t off = 0;
212         struct file * f = NULL;
213         struct audit_priv *priv;
214         struct lvfs_run_ctxt * ctxt, saved;
215         ENTRY;
216         
217         ctxt = &smb->smsi_exp->exp_obd->obd_lvfs_ctxt;
218         
219         priv = smfs_get_plg_priv(smb, SMFS_PLG_AUDIT);
220         if(!priv) {
221                 CERROR("error updating audit setting: rc = %d\n", rc);
222                 RETURN(-EINVAL);
223         }
224         
225         push_ctxt(&saved, ctxt, NULL);
226
227         f = filp_open(AUDIT_ATTR_FILE, O_RDWR|O_CREAT, 0600);
228         if (IS_ERR(f)) {
229                 CERROR("cannot get audit_setting file\n");
230                 rc = -EINVAL;
231                 goto exit;
232         }
233                 
234         rc = fsfilt->fs_write_record(f, mask, sizeof(*mask), &off, 1);
235         if (rc) {
236                 CERROR("error writting audit setting: rc = %d\n", rc);
237                 goto exit;
238         }
239         
240         priv->a_mask = (*mask);
241         
242 exit:
243         if (f)
244                 filp_close(f, 0);
245
246         pop_ctxt(&saved, ctxt, NULL);
247
248         RETURN (rc);
249 }
250
251 //set audit attributes for directory/file
252 int smfs_set_audit(struct super_block * sb, struct inode * inode,
253                    __u64 * mask)
254 {
255         void * handle = NULL;
256         struct fsfilt_operations * fsfilt = S2SMI(sb)->sm_fsfilt;
257         int rc = 0;
258         
259         ENTRY;
260         
261         if (IS_AUDIT_OP((*mask), AUDIT_FS))
262                 return smfs_set_fs_audit(sb, mask);
263
264         LASSERT(inode);
265         
266         handle = fsfilt->fs_start(inode, FSFILT_OP_SETATTR, NULL, 0);
267         if (IS_ERR(handle))
268                 RETURN(PTR_ERR(handle));
269         
270         if (fsfilt->fs_set_xattr)
271                 rc = fsfilt->fs_set_xattr(inode, handle, AUDIT_ATTR_EA,
272                                           mask, sizeof(*mask));
273
274         fsfilt->fs_commit(inode->i_sb, inode, handle, 1);
275         RETURN(rc);
276                                 
277 }
278
279 static int smfs_audit_post_op(hook_op code, struct inode * inode, void * msg,
280                               int ret, void * arg)
281 {
282         int rc = 0, len;
283         char * buffer = NULL;
284         struct audit_record * rec = NULL;
285         struct llog_rec_hdr * llh;
286         struct timeval cur_time;
287         struct audit_priv * priv = arg;
288         audit_get_op * handler = priv->audit_get_record;
289
290         //check that we are in lustre ctxt
291         if (!SMFS_IS(I2SMI(inode)->smi_flags, SMFS_PLG_AUDIT))
292                 return 0;
293         
294         if (!handler || !handler[code])
295                 return 0;
296         
297         if (smfs_audit_check(inode, code, ret, priv, msg) == 0)
298                 return 0;
299
300         ENTRY;
301         
302         do_gettimeofday(&cur_time);
303
304         OBD_ALLOC(buffer, PAGE_SIZE);
305         if (!buffer)
306                 RETURN(-ENOMEM);
307         
308         llh = (void*)buffer;
309         //fill common fields
310         rec = (void*)(buffer + sizeof(*llh));
311                
312         rec->result = ret;
313         rec->uid = current->uid;
314         rec->gid = current->gid;
315         rec->nid = current->user->nid;
316         rec->time = cur_time.tv_sec * USEC_PER_SEC + cur_time.tv_usec;
317         
318         
319         len = handler[code](inode, msg, priv, (char*)rec,
320                                            &llh->lrh_type);
321         
322         llh->lrh_len = size_round(len);
323
324         rc = llog_cat_add_rec(priv->audit_ctxt->loc_handle, llh, NULL,
325                               (void*)rec, NULL, NULL); 
326         if (rc != 0) {
327                 CERROR("Error adding audit record: %d\n", rc);
328                 rc= -EINVAL;
329         } else {
330                 audit_notify(priv->audit_ctxt->loc_handle, priv->au_id2name);
331         }
332         
333         OBD_FREE(buffer, PAGE_SIZE);
334         
335         RETURN(rc);
336 }
337
338 /* Helpers */
339 static int smfs_trans_audit (struct super_block *sb, void *arg,
340                            struct audit_priv * priv)
341 {
342         int size = 1; //one record in log per operation.
343
344         return size;
345 }
346
347 extern int mds_alloc_inode_ids(struct obd_device *, struct inode *,
348                         void *, struct lustre_id *, struct lustre_id *);
349
350 static int smfs_start_audit(struct super_block *sb, void *arg,
351                           struct audit_priv * audit_p)
352 {
353         struct smfs_super_info * smb = S2SMI(sb);
354         struct fsfilt_operations * fsfilt = smb->sm_fsfilt;
355         struct obd_device *obd = arg;
356         struct file * f;
357         int rc = 0;
358
359         ENTRY;
360
361         //is plugin already activated
362         if (SMFS_IS(smb->plg_flags, SMFS_PLG_AUDIT))
363                 RETURN(0);
364         
365         rc = audit_start_transferd();
366         if (rc) {
367                 CERROR("can't start audit transfer daemon. rc:%d\n", rc);
368                 RETURN(rc);
369         }
370         
371         if (obd && obd->obd_type && obd->obd_type->typ_name) {
372                 if (!strcmp(obd->obd_type->typ_name, "mds")) {
373                         CDEBUG(D_INODE, "Setup MDS audit handler\n");
374                         audit_mds_setup(obd, sb, audit_p);
375                 }
376                 else if (!strcmp(obd->obd_type->typ_name, "obdfilter")) {
377                         CDEBUG(D_INODE, "Setup OST audit handler\n");
378                         audit_ost_setup(obd, sb, audit_p);
379                 }
380                 else {
381                         CDEBUG(D_INODE, "Unknown obd type %s\n",
382                                obd->obd_type->typ_name);       
383                         RETURN(0);
384                 }
385         }
386         //read fs audit settings if any
387         audit_p->a_mask = AUDIT_OFF;
388
389         f = filp_open(AUDIT_ATTR_FILE, O_RDONLY, 0644);
390         if (!IS_ERR(f)) {
391                 loff_t off = 0;
392                 rc = fsfilt->fs_read_record(f, &audit_p->a_mask, 
393                                         sizeof(audit_p->a_mask), &off);
394                 if (rc) {
395                         CERROR("error reading audit setting: rc = %d\n", rc);
396                 }
397                 filp_close(f, 0);
398         }
399         
400         SMFS_SET(smb->plg_flags, SMFS_PLG_AUDIT);
401
402         RETURN(0);
403 }
404
405 int smfs_stop_audit(struct super_block *sb, void *arg,
406                   struct audit_priv * audit_p)
407 {
408         struct smfs_super_info * smb = S2SMI(sb);
409         struct llog_ctxt *ctxt = audit_p->audit_ctxt;
410         ENTRY;
411
412         if (!SMFS_IS(smb->plg_flags, SMFS_PLG_AUDIT))
413                 RETURN(0);
414
415         audit_stop_transferd();
416
417         SMFS_CLEAR(smb->plg_flags, SMFS_PLG_AUDIT);
418
419         if (ctxt->loc_llogs)
420                 ctxt->loc_llogs->llog_ctxt[LLOG_AUDIT_ORIG_CTXT] = NULL;
421
422         llog_catalog_cleanup(ctxt);
423         OBD_FREE(ctxt, sizeof(*ctxt));
424         audit_p->audit_ctxt = NULL;
425         
426         RETURN(0);
427 }
428
429 int smfs_audit_set_info(struct super_block *sb, void *arg,
430                         struct audit_priv *priv) {
431         struct plg_info_msg * msg = arg;
432         if (KEY_IS(msg->key, "id2name")) {
433                 priv->au_id2name = msg->val;
434         }
435                          
436         return 0;
437 }
438
439 typedef int (*audit_helper)(struct super_block * sb, void *msg, struct audit_priv *);
440 static audit_helper smfs_audit_helpers[PLG_HELPER_MAX] = {
441         [PLG_START]      smfs_start_audit,
442         [PLG_STOP]       smfs_stop_audit,
443         [PLG_TRANS_SIZE] smfs_trans_audit,
444         [PLG_TEST_INODE] NULL,
445         [PLG_SET_INODE]  NULL,
446         [PLG_SET_INFO]   smfs_audit_set_info,
447 };
448
449 static int smfs_audit_help_op(int code, struct super_block * sb,
450                             void * arg, void * priv)
451 {
452         int rc = 0;
453         
454         if (smfs_audit_helpers[code])
455                 rc = smfs_audit_helpers[code](sb, arg, (struct audit_priv *) priv);
456         return rc;
457 }
458
459 static int smfs_exit_audit(struct super_block *sb, 
460                            void * arg)
461 {
462         struct audit_priv * priv = arg;
463         struct smfs_plugin * plg;
464         ENTRY;
465
466         plg = smfs_deregister_plugin(sb, SMFS_PLG_AUDIT);
467         if (plg)
468                 OBD_FREE(plg, sizeof(*plg));
469         else
470                 CERROR("Cannot find AUDIT plugin while unregistering\n");
471         
472         if (priv)
473                 OBD_FREE(priv, sizeof(*priv));
474         
475         RETURN(0);
476 }
477
478 int smfs_init_audit(struct super_block *sb)
479 {
480         int rc = 0;
481         struct audit_priv * priv = NULL;
482         struct smfs_plugin * plg = NULL;
483
484         ENTRY;
485         
486         OBD_ALLOC(plg, sizeof(*plg));
487         if (!plg) {
488                 rc = -ENOMEM;
489                 goto exit;
490         }
491         
492         plg->plg_type = SMFS_PLG_AUDIT;
493         plg->plg_post_op = &smfs_audit_post_op;
494         plg->plg_helper = &smfs_audit_help_op;
495         plg->plg_exit = &smfs_exit_audit;
496
497         OBD_ALLOC(priv, sizeof(*priv));
498         if (!priv) {
499                 rc = -ENOMEM;
500                 goto exit;
501         }
502
503         plg->plg_private = priv;
504         rc = smfs_register_plugin(sb, plg);
505         if (!rc)
506                 RETURN(0);
507 exit:
508         if (priv)
509                 OBD_FREE(priv, sizeof(*priv));
510         
511         if (plg)
512                 OBD_FREE(plg, sizeof(*plg));
513
514         RETURN(rc);
515
516 }
517
518 int audit_client_log(struct super_block * sb, struct audit_msg * msg)
519 {
520         struct smfs_super_info * smb = S2SMI(sb);
521         char *buffer = NULL, *pbuf = NULL;
522         struct audit_record * rec = NULL;
523         struct llog_rec_hdr * llh;
524         struct llog_handle * ll_handle = NULL;
525         int len = 0, rc = 0;
526         struct timeval cur_time;
527         //char name[32];
528         struct audit_priv * priv;
529         
530         do_gettimeofday(&cur_time);
531         
532         priv = smfs_get_plg_priv(smb, SMFS_PLG_AUDIT);
533         if (!priv)
534                 RETURN(-EINVAL);
535         
536         ll_handle = priv->audit_ctxt->loc_handle;
537         
538         OBD_ALLOC(buffer, PAGE_SIZE);
539         if (!buffer)
540                 RETURN(-ENOMEM);
541         
542         llh = (void*)buffer;
543         llh->lrh_type = SMFS_AUDIT_GEN_REC;
544         pbuf = buffer + sizeof(*llh);
545
546         //fill common fields
547         rec = (void*)(pbuf);
548         rec->opcode = msg->code;
549         rec->result = msg->result;
550         rec->uid = msg->uid;
551         rec->gid = msg->gid;
552         rec->nid = msg->nid;
553         rec->time = cur_time.tv_sec * USEC_PER_SEC + cur_time.tv_usec;
554         pbuf += sizeof(*rec);
555         
556         switch (msg->code) {
557                 case AUDIT_READ:    
558                 case AUDIT_WRITE:
559                 case AUDIT_MMAP:
560                 case AUDIT_OPEN:
561                 case AUDIT_STAT:
562                         len = audit_rec_from_id(&pbuf, &msg->id);
563                         break;
564                 default:
565                         CERROR("Unknown code %i in audit_msg\n", msg->code);
566         }
567         
568         llh->lrh_len = size_round(len);
569
570         rc = llog_cat_add_rec(ll_handle, llh, NULL, (void*)rec, NULL, NULL);
571         if (rc != 0) {
572                 CERROR("Error adding audit client record: %d\n", rc);
573                 rc= -EINVAL;
574         } else {
575                 audit_notify(ll_handle, priv->au_id2name);
576         }
577         
578         OBD_FREE(buffer, PAGE_SIZE);
579         return rc;
580 }
581