15440Sjm199354 /* 25440Sjm199354 * CDDL HEADER START 35440Sjm199354 * 45440Sjm199354 * The contents of this file are subject to the terms of the 55440Sjm199354 * Common Development and Distribution License (the "License"). 65440Sjm199354 * You may not use this file except in compliance with the License. 75440Sjm199354 * 85440Sjm199354 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95440Sjm199354 * or http://www.opensolaris.org/os/licensing. 105440Sjm199354 * See the License for the specific language governing permissions 115440Sjm199354 * and limitations under the License. 125440Sjm199354 * 135440Sjm199354 * When distributing Covered Code, include this CDDL HEADER in each 145440Sjm199354 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155440Sjm199354 * If applicable, add the following below this CDDL HEADER, with the 165440Sjm199354 * fields enclosed by brackets "[]" replaced with your own identifying 175440Sjm199354 * information: Portions Copyright [yyyy] [name of copyright owner] 185440Sjm199354 * 195440Sjm199354 * CDDL HEADER END 205440Sjm199354 */ 215440Sjm199354 225440Sjm199354 /* 23*5931Sjm199354 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 245440Sjm199354 * Use is subject to license terms. 255440Sjm199354 */ 265440Sjm199354 275440Sjm199354 #pragma ident "%Z%%M% %I% %E% SMI" 285440Sjm199354 295440Sjm199354 #include <sys/stat.h> 305440Sjm199354 #include <sys/ddi.h> 315440Sjm199354 #include <sys/sunddi.h> 325440Sjm199354 #include <sys/time.h> 335440Sjm199354 #include <sys/varargs.h> 345440Sjm199354 #include <sys/conf.h> 355440Sjm199354 #include <sys/modctl.h> 365440Sjm199354 #include <sys/cmn_err.h> 375440Sjm199354 #include <sys/vnode.h> 385440Sjm199354 #include <fs/fs_subr.h> 395440Sjm199354 #include <sys/types.h> 405440Sjm199354 #include <sys/file.h> 415440Sjm199354 #include <sys/disp.h> 425440Sjm199354 #include <sys/sdt.h> 435440Sjm199354 #include <sys/cred.h> 445440Sjm199354 #include <sys/vscan.h> 455440Sjm199354 465440Sjm199354 #define VS_TASKQ_NUM_THREADS VS_DRV_MAX_FILES 475440Sjm199354 #define VS_EXT_RECURSE_DEPTH 8 485440Sjm199354 #define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C)) 495440Sjm199354 505440Sjm199354 /* represents request received from filesystem - currently only use vp */ 515440Sjm199354 typedef struct vscan_fs_req { 525440Sjm199354 vnode_t *vsr_vp; 535440Sjm199354 } vscan_fs_req_t; 545440Sjm199354 555440Sjm199354 /* 565440Sjm199354 * vscan_svc_files - table of files being scanned 575440Sjm199354 * 585440Sjm199354 * The index into this table is passed in the door call to 595440Sjm199354 * vscand. vscand uses the idx to determine which minor node 605440Sjm199354 * to open to read the file data. Within the kernel driver 615440Sjm199354 * the minor device number can thus be used to identify the 625440Sjm199354 * table index to get the appropriate vnode. 635440Sjm199354 * 645440Sjm199354 * Instance 0 is reserved for the daemon/driver control 655440Sjm199354 * interface: enable/configure/disable 665440Sjm199354 */ 675440Sjm199354 typedef struct vscan_file { 685440Sjm199354 vscan_fs_req_t vsf_req; 695440Sjm199354 uint32_t vsf_wait_count; 70*5931Sjm199354 kcondvar_t vsf_cv; /* wait for in progress scan */ 715440Sjm199354 uint8_t vsf_quarantined; 725440Sjm199354 uint8_t vsf_modified; 735440Sjm199354 uint64_t vsf_size; 74*5931Sjm199354 timestruc_t vsf_mtime; 755440Sjm199354 vs_scanstamp_t vsf_scanstamp; 76*5931Sjm199354 uint32_t vsf_result; 775440Sjm199354 uint32_t vsf_access; 785440Sjm199354 } vscan_file_t; 795440Sjm199354 805440Sjm199354 static vscan_file_t vscan_svc_files[VS_DRV_MAX_FILES + 1]; 815440Sjm199354 static kcondvar_t vscan_svc_cv; /* wait for slot in vscan_svc_files */ 825440Sjm199354 static int vscan_svc_wait_count = 0; /* # waiting for slot in vscan_svc_files */ 835440Sjm199354 static int vscan_svc_req_count = 0; /* # scan requests */ 845440Sjm199354 855440Sjm199354 static taskq_t *vscan_svc_taskq = NULL; 865440Sjm199354 static boolean_t vscan_svc_enabled = B_FALSE; 875440Sjm199354 885440Sjm199354 /* 895440Sjm199354 * vscan_svc_mutex protects the data pertaining to scan requests: 905440Sjm199354 * file table - vscan_svc_files 915440Sjm199354 * counts - vscan_svc_wait_count, vscan_svc_req_count 925440Sjm199354 */ 935440Sjm199354 static kmutex_t vscan_svc_mutex; 945440Sjm199354 955440Sjm199354 /* 965440Sjm199354 * vscan_svc_cfg_mutex protects the configuration data: 975440Sjm199354 * vscan_svc_config, vscan_svc_types 985440Sjm199354 */ 995440Sjm199354 static kmutex_t vscan_svc_cfg_mutex; 1005440Sjm199354 1015440Sjm199354 /* configuration data - for virus scan exemption */ 1025440Sjm199354 static vs_config_t vscan_svc_config; 1035440Sjm199354 static char *vscan_svc_types[VS_TYPES_MAX]; 1045440Sjm199354 1055440Sjm199354 /* local functions */ 1065440Sjm199354 int vscan_svc_scan_file(vnode_t *, cred_t *, int); 1075440Sjm199354 void vscan_svc_taskq_callback(void *); 1085440Sjm199354 static int vscan_svc_exempt_file(vnode_t *, boolean_t *); 1095440Sjm199354 static int vscan_svc_exempt_filetype(char *); 1105440Sjm199354 static int vscan_svc_match_ext(char *, char *, int); 1115440Sjm199354 static int vscan_svc_do_scan(vscan_fs_req_t *); 1125440Sjm199354 static int vscan_svc_wait_for_scan(vnode_t *); 1135440Sjm199354 static int vscan_svc_insert_file(vscan_fs_req_t *); 1145440Sjm199354 static void vscan_svc_release_file(int); 1155440Sjm199354 static int vscan_svc_find_slot(void); 116*5931Sjm199354 static void vscan_svc_process_scan_result(int); 1175440Sjm199354 static void vscan_svc_notify_scan_complete(int); 1185440Sjm199354 static int vscan_svc_getattr(int); 119*5931Sjm199354 static int vscan_svc_setattr(int, int); 1205440Sjm199354 1215440Sjm199354 static vs_scan_req_t *vscan_svc_populate_req(int); 1225440Sjm199354 static void vscan_svc_parse_rsp(int, vs_scan_req_t *); 1235440Sjm199354 1245440Sjm199354 1255440Sjm199354 /* 1265440Sjm199354 * vscan_svc_init 1275440Sjm199354 */ 1285440Sjm199354 int 1295440Sjm199354 vscan_svc_init() 1305440Sjm199354 { 1315440Sjm199354 mutex_init(&vscan_svc_mutex, NULL, MUTEX_DRIVER, NULL); 1325440Sjm199354 mutex_init(&vscan_svc_cfg_mutex, NULL, MUTEX_DRIVER, NULL); 1335440Sjm199354 (void) memset(&vscan_svc_files, 0, sizeof (vscan_svc_files)); 1345440Sjm199354 cv_init(&vscan_svc_cv, NULL, CV_DEFAULT, NULL); 1355440Sjm199354 1365440Sjm199354 return (0); 1375440Sjm199354 } 1385440Sjm199354 1395440Sjm199354 /* 1405440Sjm199354 * vscan_svc_fini 1415440Sjm199354 */ 1425440Sjm199354 void 1435440Sjm199354 vscan_svc_fini() 1445440Sjm199354 { 1455440Sjm199354 ASSERT(vscan_svc_enabled == B_FALSE); 1465440Sjm199354 ASSERT(vscan_svc_in_use() == B_FALSE); 1475440Sjm199354 1485440Sjm199354 cv_destroy(&vscan_svc_cv); 1495440Sjm199354 mutex_destroy(&vscan_svc_mutex); 1505440Sjm199354 mutex_destroy(&vscan_svc_cfg_mutex); 1515440Sjm199354 } 1525440Sjm199354 1535440Sjm199354 /* 1545440Sjm199354 * vscan_svc_enable 1555440Sjm199354 */ 1565440Sjm199354 void 157*5931Sjm199354 vscan_svc_enable(void) 1585440Sjm199354 { 159*5931Sjm199354 mutex_enter(&vscan_svc_mutex); 160*5931Sjm199354 vscan_svc_enabled = B_TRUE; 161*5931Sjm199354 162*5931Sjm199354 if (vscan_svc_taskq == NULL) { 163*5931Sjm199354 if ((vscan_svc_taskq = taskq_create("vscan", 164*5931Sjm199354 VS_TASKQ_NUM_THREADS, MINCLSYSPRI, 1, 165*5931Sjm199354 INT_MAX, TASKQ_DYNAMIC)) == NULL) { 166*5931Sjm199354 cmn_err(CE_WARN, "All scan requests " 167*5931Sjm199354 "will be processed synchronously"); 168*5931Sjm199354 } 169*5931Sjm199354 } 170*5931Sjm199354 171*5931Sjm199354 fs_vscan_register(vscan_svc_scan_file); 172*5931Sjm199354 mutex_exit(&vscan_svc_mutex); 173*5931Sjm199354 } 174*5931Sjm199354 1755440Sjm199354 176*5931Sjm199354 /* 177*5931Sjm199354 * vscan_svc_disable 178*5931Sjm199354 */ 179*5931Sjm199354 void 180*5931Sjm199354 vscan_svc_disable(void) 181*5931Sjm199354 { 182*5931Sjm199354 mutex_enter(&vscan_svc_mutex); 183*5931Sjm199354 vscan_svc_enabled = B_FALSE; 184*5931Sjm199354 fs_vscan_register(NULL); 185*5931Sjm199354 186*5931Sjm199354 if (vscan_svc_taskq) { 187*5931Sjm199354 taskq_destroy(vscan_svc_taskq); 188*5931Sjm199354 vscan_svc_taskq = NULL; 189*5931Sjm199354 } 190*5931Sjm199354 mutex_exit(&vscan_svc_mutex); 1915440Sjm199354 } 1925440Sjm199354 193*5931Sjm199354 194*5931Sjm199354 195*5931Sjm199354 /* 196*5931Sjm199354 * vscan_svc_is_enabled 197*5931Sjm199354 */ 198*5931Sjm199354 boolean_t 199*5931Sjm199354 vscan_svc_is_enabled() 200*5931Sjm199354 { 201*5931Sjm199354 return (vscan_svc_enabled); 202*5931Sjm199354 } 203*5931Sjm199354 204*5931Sjm199354 2055440Sjm199354 /* 2065440Sjm199354 * vscan_svc_in_use 207*5931Sjm199354 * 208*5931Sjm199354 * The vscan driver is considered to be in use if it is 209*5931Sjm199354 * enabled or if there are in-progress scan requests. 210*5931Sjm199354 * Used to determine whether the driver can be unloaded. 2115440Sjm199354 */ 2125440Sjm199354 boolean_t 2135440Sjm199354 vscan_svc_in_use() 2145440Sjm199354 { 2155440Sjm199354 boolean_t rc; 2165440Sjm199354 2175440Sjm199354 mutex_enter(&vscan_svc_mutex); 218*5931Sjm199354 rc = (vscan_svc_enabled == B_TRUE) || (vscan_svc_req_count > 0); 2195440Sjm199354 mutex_exit(&vscan_svc_mutex); 2205440Sjm199354 2215440Sjm199354 return (rc); 2225440Sjm199354 } 2235440Sjm199354 2245440Sjm199354 /* 2255440Sjm199354 * vscan_svc_get_vnode 2265440Sjm199354 * 2275440Sjm199354 * Get the file vnode indexed by idx. 2285440Sjm199354 * Returns NULL if idx not valid. 2295440Sjm199354 */ 2305440Sjm199354 vnode_t * 2315440Sjm199354 vscan_svc_get_vnode(int idx) 2325440Sjm199354 { 2335440Sjm199354 ASSERT(idx > 0); 2345440Sjm199354 ASSERT(idx <= VS_DRV_MAX_FILES); 2355440Sjm199354 2365440Sjm199354 if ((idx <= 0) || (idx > VS_DRV_MAX_FILES)) 2375440Sjm199354 return (NULL); 2385440Sjm199354 else 2395440Sjm199354 return (vscan_svc_files[idx].vsf_req.vsr_vp); 2405440Sjm199354 } 2415440Sjm199354 2425440Sjm199354 2435440Sjm199354 /* 2445440Sjm199354 * vscan_svc_scan_file 2455440Sjm199354 * 2465440Sjm199354 * This function is the entry point for the file system to 2475440Sjm199354 * request that a file be virus scanned. 2485440Sjm199354 * 2495440Sjm199354 * Asynchronous requests: 2505440Sjm199354 * If an async scan request cannot be queued it is discarded. 2515440Sjm199354 * By definition the caller of an async request is not dependent 2525440Sjm199354 * on the outcome of the result. Although the file will thus 2535440Sjm199354 * not be scanned at this time, it will be scanned 2545440Sjm199354 * (synchronously) on subsequent access. 2555440Sjm199354 * This scenario should not occur during normal operation. 2565440Sjm199354 * 2575440Sjm199354 * Before queuing an async request do VN_HOLD(vp). VN_RELE(vp) 2585440Sjm199354 * will be done when the scan completes or if the request 2595440Sjm199354 * couldn't be queued. 2605440Sjm199354 * 2615440Sjm199354 * The vscan_fs_req_t, allocated to hold the request information 2625440Sjm199354 * passed from the fs, will be free'd when the scan completes. 2635440Sjm199354 */ 2645440Sjm199354 int 2655440Sjm199354 vscan_svc_scan_file(vnode_t *vp, cred_t *cr, int async) 2665440Sjm199354 { 2675440Sjm199354 int rc = 0; 2685440Sjm199354 vscan_fs_req_t *req; 2695440Sjm199354 boolean_t allow; 2705440Sjm199354 2715440Sjm199354 mutex_enter(&vscan_svc_mutex); 2725440Sjm199354 2735440Sjm199354 if ((vp == NULL) || (vp->v_path == NULL) || cr == NULL) { 2745440Sjm199354 mutex_exit(&vscan_svc_mutex); 2755440Sjm199354 return (0); 2765440Sjm199354 } 2775440Sjm199354 2785440Sjm199354 DTRACE_PROBE2(vscan__scan__file, char *, vp->v_path, int, async); 2795440Sjm199354 2805440Sjm199354 /* check if size or type exempts file from scanning */ 2815440Sjm199354 if (vscan_svc_exempt_file(vp, &allow)) { 2825440Sjm199354 mutex_exit(&vscan_svc_mutex); 2835440Sjm199354 if ((allow == B_TRUE) || (async != 0)) 2845440Sjm199354 return (0); 2855440Sjm199354 2865440Sjm199354 return (EACCES); 2875440Sjm199354 } 2885440Sjm199354 2895440Sjm199354 vscan_svc_req_count++; 2905440Sjm199354 mutex_exit(&vscan_svc_mutex); 2915440Sjm199354 2925440Sjm199354 req = kmem_zalloc(sizeof (vscan_fs_req_t), KM_SLEEP); 2935440Sjm199354 req->vsr_vp = vp; 2945440Sjm199354 2955440Sjm199354 if (async) { 2965440Sjm199354 VN_HOLD(vp); 2975440Sjm199354 if (vscan_svc_taskq && 2985440Sjm199354 taskq_dispatch(vscan_svc_taskq, vscan_svc_taskq_callback, 2995440Sjm199354 (void *)req, TQ_SLEEP)) { 3005440Sjm199354 return (0); 3015440Sjm199354 } else { 3025440Sjm199354 VN_RELE(vp); 3035440Sjm199354 kmem_free(req, sizeof (vscan_fs_req_t)); 3045440Sjm199354 } 3055440Sjm199354 } else { 3065440Sjm199354 rc = vscan_svc_do_scan(req); 3075440Sjm199354 kmem_free(req, sizeof (vscan_fs_req_t)); 3085440Sjm199354 } 3095440Sjm199354 3105440Sjm199354 mutex_enter(&vscan_svc_mutex); 3115440Sjm199354 vscan_svc_req_count--; 3125440Sjm199354 mutex_exit(&vscan_svc_mutex); 3135440Sjm199354 3145440Sjm199354 return (rc); 3155440Sjm199354 } 3165440Sjm199354 3175440Sjm199354 3185440Sjm199354 /* 3195440Sjm199354 * vscan_svc_taskq_callback 3205440Sjm199354 * 3215440Sjm199354 * Callback function for async scan requests 3225440Sjm199354 */ 3235440Sjm199354 void 3245440Sjm199354 vscan_svc_taskq_callback(void *data) 3255440Sjm199354 { 3265440Sjm199354 vscan_fs_req_t *req = (vscan_fs_req_t *)data; 3275440Sjm199354 3285440Sjm199354 (void) vscan_svc_do_scan(req); 3295440Sjm199354 VN_RELE(req->vsr_vp); /* VN_HOLD done before request queued */ 3305440Sjm199354 kmem_free(req, sizeof (vscan_fs_req_t)); 3315440Sjm199354 3325440Sjm199354 mutex_enter(&vscan_svc_mutex); 3335440Sjm199354 vscan_svc_req_count--; 3345440Sjm199354 mutex_exit(&vscan_svc_mutex); 3355440Sjm199354 } 3365440Sjm199354 3375440Sjm199354 3385440Sjm199354 /* 3395440Sjm199354 * vscan_svc_do_scan 3405440Sjm199354 * 3415440Sjm199354 * Should never be called directly. Invoke via vscan_svc_scan_file() 3425440Sjm199354 * If scan is in progress wait for it to complete, otherwise 3435440Sjm199354 * initiate door call to scan the file. 3445440Sjm199354 */ 3455440Sjm199354 static int 3465440Sjm199354 vscan_svc_do_scan(vscan_fs_req_t *req) 3475440Sjm199354 { 348*5931Sjm199354 int rc = -1, idx; 3495440Sjm199354 vs_scan_req_t *scan_req; 350*5931Sjm199354 vscan_file_t *svc_file; 3515440Sjm199354 3525440Sjm199354 mutex_enter(&vscan_svc_mutex); 3535440Sjm199354 3545440Sjm199354 /* 3555440Sjm199354 * if a scan is in progress on the files vscan_svc_wait_for_scan will 3565440Sjm199354 * wait for it to complete and return the idx of the scan request. 3575440Sjm199354 * Otherwise it will return -1 and we will initiate a scan here. 3585440Sjm199354 */ 359*5931Sjm199354 if ((idx = vscan_svc_wait_for_scan(req->vsr_vp)) != -1) { 360*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 361*5931Sjm199354 } else { 3625440Sjm199354 /* insert the scan request into vscan_svc_files */ 3635440Sjm199354 idx = vscan_svc_insert_file(req); 364*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 3655440Sjm199354 3665440Sjm199354 if (vscan_svc_enabled) { 3675440Sjm199354 if (vscan_svc_getattr(idx) == 0) { 3685440Sjm199354 /* valid scan_req ptr guaranteed */ 3695440Sjm199354 scan_req = vscan_svc_populate_req(idx); 3705440Sjm199354 mutex_exit(&vscan_svc_mutex); 371*5931Sjm199354 if (vscan_drv_create_node(idx) == B_TRUE) 372*5931Sjm199354 rc = vscan_door_scan_file(scan_req); 3735440Sjm199354 mutex_enter(&vscan_svc_mutex); 374*5931Sjm199354 if (rc == 0) 3755440Sjm199354 vscan_svc_parse_rsp(idx, scan_req); 3765440Sjm199354 kmem_free(scan_req, sizeof (vs_scan_req_t)); 377*5931Sjm199354 378*5931Sjm199354 /* process scan result */ 379*5931Sjm199354 vscan_svc_process_scan_result(idx); 380*5931Sjm199354 DTRACE_PROBE2(vscan__result, int, 381*5931Sjm199354 svc_file->vsf_result, int, 382*5931Sjm199354 svc_file->vsf_access); 3835440Sjm199354 } else { 384*5931Sjm199354 /* if getattr fails: log error, deny access */ 3855440Sjm199354 cmn_err(CE_WARN, "Can't access xattr for %s\n", 386*5931Sjm199354 svc_file->vsf_req.vsr_vp->v_path); 387*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_DENY; 3885440Sjm199354 } 3895440Sjm199354 } else { 3905440Sjm199354 /* if vscan not enabled (shutting down), allow ACCESS */ 391*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_ALLOW; 3925440Sjm199354 } 3935440Sjm199354 } 3945440Sjm199354 3955440Sjm199354 /* When a scan completes the result is saved in vscan_svc_files */ 396*5931Sjm199354 rc = (svc_file->vsf_access == VS_ACCESS_ALLOW) ? 0 : EACCES; 3975440Sjm199354 3985440Sjm199354 /* wake threads waiting for result, or for a slot in vscan_svc_files */ 3995440Sjm199354 vscan_svc_notify_scan_complete(idx); 4005440Sjm199354 4015440Sjm199354 /* remove the entry from vscan_svc_files if nobody else is waiting */ 4025440Sjm199354 vscan_svc_release_file(idx); 4035440Sjm199354 4045440Sjm199354 mutex_exit(&vscan_svc_mutex); 4055440Sjm199354 4065440Sjm199354 return (rc); 4075440Sjm199354 } 4085440Sjm199354 409*5931Sjm199354 410*5931Sjm199354 /* 411*5931Sjm199354 * vscan_svc_process_scan_result 412*5931Sjm199354 * 413*5931Sjm199354 * Sets vsf_access and updates file attributes based on vsf_result, 414*5931Sjm199354 * as follows: 415*5931Sjm199354 * 416*5931Sjm199354 * VS_STATUS_INFECTED 417*5931Sjm199354 * deny access, set quarantine attribute, clear scanstamp 418*5931Sjm199354 * VS_STATUS_CLEAN 419*5931Sjm199354 * allow access, set scanstamp, 420*5931Sjm199354 * if file not modified since scan initiated, clear modified attribute 421*5931Sjm199354 * VS_STATUS_NO_SCAN 422*5931Sjm199354 * deny access if file quarantined, otherwise allow access 423*5931Sjm199354 * VS_STATUS_UNDEFINED, VS_STATUS_ERROR 424*5931Sjm199354 * deny access if file quarantined, modified or no scanstamp 425*5931Sjm199354 * otherwise, allow access 426*5931Sjm199354 */ 427*5931Sjm199354 static void 428*5931Sjm199354 vscan_svc_process_scan_result(int idx) 429*5931Sjm199354 { 430*5931Sjm199354 struct vattr attr; 431*5931Sjm199354 vnode_t *vp; 432*5931Sjm199354 timestruc_t *mtime; 433*5931Sjm199354 vscan_file_t *svc_file; 434*5931Sjm199354 435*5931Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 436*5931Sjm199354 437*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 438*5931Sjm199354 439*5931Sjm199354 switch (svc_file->vsf_result) { 440*5931Sjm199354 case VS_STATUS_INFECTED: 441*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_DENY; 442*5931Sjm199354 svc_file->vsf_quarantined = 1; 443*5931Sjm199354 svc_file->vsf_scanstamp[0] = '\0'; 444*5931Sjm199354 (void) vscan_svc_setattr(idx, 445*5931Sjm199354 XAT_AV_QUARANTINED | XAT_AV_SCANSTAMP); 446*5931Sjm199354 return; 447*5931Sjm199354 448*5931Sjm199354 case VS_STATUS_CLEAN: 449*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_ALLOW; 450*5931Sjm199354 451*5931Sjm199354 /* if mtime has changed, don't clear the modified attribute */ 452*5931Sjm199354 vp = svc_file->vsf_req.vsr_vp; 453*5931Sjm199354 mtime = &(svc_file->vsf_mtime); 454*5931Sjm199354 attr.va_mask = AT_MTIME; 455*5931Sjm199354 if ((VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) || 456*5931Sjm199354 (mtime->tv_sec != attr.va_mtime.tv_sec) || 457*5931Sjm199354 (mtime->tv_nsec != attr.va_mtime.tv_nsec)) { 458*5931Sjm199354 DTRACE_PROBE1(vscan__mtime__changed, vscan_file_t *, 459*5931Sjm199354 svc_file); 460*5931Sjm199354 (void) vscan_svc_setattr(idx, XAT_AV_SCANSTAMP); 461*5931Sjm199354 return; 462*5931Sjm199354 } 463*5931Sjm199354 464*5931Sjm199354 svc_file->vsf_modified = 0; 465*5931Sjm199354 (void) vscan_svc_setattr(idx, 466*5931Sjm199354 XAT_AV_SCANSTAMP | XAT_AV_MODIFIED); 467*5931Sjm199354 return; 468*5931Sjm199354 469*5931Sjm199354 case VS_STATUS_NO_SCAN: 470*5931Sjm199354 if (svc_file->vsf_quarantined) 471*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_DENY; 472*5931Sjm199354 else 473*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_ALLOW; 474*5931Sjm199354 return; 475*5931Sjm199354 476*5931Sjm199354 case VS_STATUS_ERROR: 477*5931Sjm199354 case VS_STATUS_UNDEFINED: 478*5931Sjm199354 default: 479*5931Sjm199354 if ((svc_file->vsf_quarantined) || 480*5931Sjm199354 (svc_file->vsf_modified) || 481*5931Sjm199354 (svc_file->vsf_scanstamp[0] == '\0')) 482*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_DENY; 483*5931Sjm199354 else 484*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_ALLOW; 485*5931Sjm199354 return; 486*5931Sjm199354 } 487*5931Sjm199354 } 488*5931Sjm199354 489*5931Sjm199354 4905440Sjm199354 /* 4915440Sjm199354 * vscan_svc_wait_for_scan 4925440Sjm199354 * 4935440Sjm199354 * Search for vp in vscan_svc_files. If vp already exists in 4945440Sjm199354 * vscan_svc_files scan is already in progress on file so wait 4955440Sjm199354 * for the inprogress scan to complete. 4965440Sjm199354 * 4975440Sjm199354 * Returns: idx of file waited for 4985440Sjm199354 * -1 if file not already scanning 4995440Sjm199354 */ 5005440Sjm199354 static int 5015440Sjm199354 vscan_svc_wait_for_scan(vnode_t *vp) 5025440Sjm199354 { 5035440Sjm199354 int idx; 504*5931Sjm199354 vscan_file_t *svc_file; 5055440Sjm199354 5065440Sjm199354 ASSERT(vp); 5075440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 5085440Sjm199354 5095440Sjm199354 for (idx = 1; idx <= VS_DRV_MAX_FILES; idx++) { 5105440Sjm199354 if (vscan_svc_files[idx].vsf_req.vsr_vp == vp) 5115440Sjm199354 break; 5125440Sjm199354 } 5135440Sjm199354 5145440Sjm199354 /* file not found in table thus not currently being scanned */ 5155440Sjm199354 if (idx > VS_DRV_MAX_FILES) 5165440Sjm199354 return (-1); 5175440Sjm199354 5185440Sjm199354 /* file found - wait for scan to complete */ 519*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 520*5931Sjm199354 svc_file->vsf_wait_count++; 5215440Sjm199354 522*5931Sjm199354 DTRACE_PROBE2(vscan__wait__scan, vscan_file_t *, svc_file, int, idx); 5235440Sjm199354 524*5931Sjm199354 while (svc_file->vsf_access == VS_ACCESS_UNDEFINED) 525*5931Sjm199354 cv_wait(&(svc_file->vsf_cv), &vscan_svc_mutex); 5265440Sjm199354 527*5931Sjm199354 svc_file->vsf_wait_count--; 5285440Sjm199354 5295440Sjm199354 return (idx); 5305440Sjm199354 } 5315440Sjm199354 5325440Sjm199354 5335440Sjm199354 /* 5345440Sjm199354 * vscan_svc_find_slot 5355440Sjm199354 * 5365440Sjm199354 * Find empty slot in vscan_svc_files table. 5375440Sjm199354 * 5385440Sjm199354 * Returns idx of slot, or -1 if not found 5395440Sjm199354 */ 5405440Sjm199354 static int 5415440Sjm199354 vscan_svc_find_slot(void) 5425440Sjm199354 { 543*5931Sjm199354 int idx; 5445440Sjm199354 5455440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 546*5931Sjm199354 for (idx = 1; idx <= VS_DRV_MAX_FILES; idx++) { 547*5931Sjm199354 if (vscan_svc_files[idx].vsf_req.vsr_vp == NULL) 5485440Sjm199354 return (idx); 5495440Sjm199354 } 5505440Sjm199354 5515440Sjm199354 return (-1); 5525440Sjm199354 } 5535440Sjm199354 5545440Sjm199354 5555440Sjm199354 /* 5565440Sjm199354 * vscan_svc_insert_file 5575440Sjm199354 * 5585440Sjm199354 * Find the next available flot in vscan_svc_files and 5595440Sjm199354 * initialize it for the scan request. If no slot is 5605440Sjm199354 * available, vscan_svc_find_slot will wait for one. 5615440Sjm199354 * 5625440Sjm199354 * Returns: idx of scan request in vscan_svc_files table 5635440Sjm199354 */ 5645440Sjm199354 static int 5655440Sjm199354 vscan_svc_insert_file(vscan_fs_req_t *req) 5665440Sjm199354 { 5675440Sjm199354 int idx; 568*5931Sjm199354 vscan_file_t *svc_file; 5695440Sjm199354 5705440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 5715440Sjm199354 5725440Sjm199354 while ((idx = vscan_svc_find_slot()) == -1) { 573*5931Sjm199354 DTRACE_PROBE1(vscan__wait__slot, char *, req->vsr_vp->v_path); 5745440Sjm199354 vscan_svc_wait_count++; 5755440Sjm199354 cv_wait(&(vscan_svc_cv), &vscan_svc_mutex); 5765440Sjm199354 vscan_svc_wait_count--; 5775440Sjm199354 } 5785440Sjm199354 579*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 580*5931Sjm199354 581*5931Sjm199354 (void) memset(svc_file, 0, sizeof (vscan_file_t)); 582*5931Sjm199354 svc_file->vsf_req = *req; 583*5931Sjm199354 svc_file->vsf_modified = 1; 584*5931Sjm199354 svc_file->vsf_result = VS_STATUS_UNDEFINED; 585*5931Sjm199354 svc_file->vsf_access = VS_ACCESS_UNDEFINED; 586*5931Sjm199354 cv_init(&(svc_file->vsf_cv), NULL, CV_DEFAULT, NULL); 5875440Sjm199354 5885440Sjm199354 DTRACE_PROBE2(vscan__insert, char *, req->vsr_vp->v_path, int, idx); 5895440Sjm199354 return (idx); 5905440Sjm199354 } 5915440Sjm199354 5925440Sjm199354 5935440Sjm199354 /* 5945440Sjm199354 * vscan_svc_release_file 5955440Sjm199354 * 5965440Sjm199354 * Release the file (free the slot in vscan_svc_files) 5975440Sjm199354 * if no thread is waiting on it. 5985440Sjm199354 */ 5995440Sjm199354 static void 6005440Sjm199354 vscan_svc_release_file(int idx) 6015440Sjm199354 { 602*5931Sjm199354 vscan_file_t *svc_file; 6035440Sjm199354 6045440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 605*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 6065440Sjm199354 607*5931Sjm199354 if (svc_file->vsf_wait_count != 0) 6085440Sjm199354 return; 6095440Sjm199354 610*5931Sjm199354 DTRACE_PROBE2(vscan__release, char *, 611*5931Sjm199354 svc_file->vsf_req.vsr_vp->v_path, int, idx); 612*5931Sjm199354 613*5931Sjm199354 cv_destroy(&(svc_file->vsf_cv)); 614*5931Sjm199354 (void) memset(svc_file, 0, sizeof (vscan_file_t)); 6155440Sjm199354 } 6165440Sjm199354 6175440Sjm199354 6185440Sjm199354 /* 6195440Sjm199354 * vscan_svc_populate_req 6205440Sjm199354 * 6215440Sjm199354 * Allocate a scan request to be sent to vscand, populating it 6225440Sjm199354 * from the data in vscan_svc_files[idx]. 6235440Sjm199354 * 6245440Sjm199354 * Returns: scan request object 6255440Sjm199354 */ 6265440Sjm199354 static vs_scan_req_t * 6275440Sjm199354 vscan_svc_populate_req(int idx) 6285440Sjm199354 { 6295440Sjm199354 vs_scan_req_t *scan_req; 6305440Sjm199354 vscan_fs_req_t *req; 631*5931Sjm199354 vscan_file_t *svc_file; 6325440Sjm199354 6335440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 6345440Sjm199354 635*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 636*5931Sjm199354 req = &(svc_file->vsf_req); 6375440Sjm199354 scan_req = kmem_zalloc(sizeof (vs_scan_req_t), KM_SLEEP); 6385440Sjm199354 6395440Sjm199354 scan_req->vsr_id = idx; 6405440Sjm199354 (void) strncpy(scan_req->vsr_path, req->vsr_vp->v_path, MAXPATHLEN); 641*5931Sjm199354 scan_req->vsr_size = svc_file->vsf_size; 642*5931Sjm199354 scan_req->vsr_modified = svc_file->vsf_modified; 643*5931Sjm199354 scan_req->vsr_quarantined = svc_file->vsf_quarantined; 6445440Sjm199354 scan_req->vsr_flags = 0; 6455440Sjm199354 (void) strncpy(scan_req->vsr_scanstamp, 646*5931Sjm199354 svc_file->vsf_scanstamp, sizeof (vs_scanstamp_t)); 6475440Sjm199354 6485440Sjm199354 return (scan_req); 6495440Sjm199354 } 6505440Sjm199354 6515440Sjm199354 6525440Sjm199354 /* 6535440Sjm199354 * vscan_svc_parse_rsp 6545440Sjm199354 * 6555440Sjm199354 * Parse scan response data and save in vscan_svc_files[idx] 6565440Sjm199354 */ 6575440Sjm199354 static void 6585440Sjm199354 vscan_svc_parse_rsp(int idx, vs_scan_req_t *scan_req) 6595440Sjm199354 { 660*5931Sjm199354 vscan_file_t *svc_file; 661*5931Sjm199354 6625440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 6635440Sjm199354 664*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 665*5931Sjm199354 svc_file->vsf_result = scan_req->vsr_result; 666*5931Sjm199354 (void) strncpy(svc_file->vsf_scanstamp, 6675440Sjm199354 scan_req->vsr_scanstamp, sizeof (vs_scanstamp_t)); 6685440Sjm199354 } 6695440Sjm199354 6705440Sjm199354 6715440Sjm199354 /* 6725440Sjm199354 * vscan_svc_notify_scan_complete 6735440Sjm199354 * 674*5931Sjm199354 * signal vscan_svc_files.vsf_cv and vscan_svc_cv to wake 675*5931Sjm199354 * threads waiting for the scan result for the specified 676*5931Sjm199354 * file (vscan_svc_files[idx].vsf_cv) or for a slot in 677*5931Sjm199354 * vscan_svc_files table (vscan_svc_cv) 6785440Sjm199354 */ 6795440Sjm199354 static void 6805440Sjm199354 vscan_svc_notify_scan_complete(int idx) 6815440Sjm199354 { 682*5931Sjm199354 vscan_file_t *svc_file; 683*5931Sjm199354 6845440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 6855440Sjm199354 686*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 687*5931Sjm199354 6885440Sjm199354 /* if someone waiting for result, cv_signal */ 689*5931Sjm199354 if (svc_file->vsf_wait_count > 0) 690*5931Sjm199354 cv_signal(&(svc_file->vsf_cv)); 6915440Sjm199354 6925440Sjm199354 /* signal vscan_svc_cv if any threads waiting for a slot */ 6935440Sjm199354 if (vscan_svc_wait_count > 0) 6945440Sjm199354 cv_signal(&vscan_svc_cv); 6955440Sjm199354 } 6965440Sjm199354 6975440Sjm199354 6985440Sjm199354 /* 6995440Sjm199354 * vscan_svc_getattr 7005440Sjm199354 * 701*5931Sjm199354 * Get the vscan related system attributes, AT_SIZE & AT_MTIME. 7025440Sjm199354 */ 7035440Sjm199354 static int 7045440Sjm199354 vscan_svc_getattr(int idx) 7055440Sjm199354 { 7065440Sjm199354 xvattr_t xvattr; 7075440Sjm199354 xoptattr_t *xoap = NULL; 7085440Sjm199354 vnode_t *vp; 709*5931Sjm199354 vscan_file_t *svc_file; 7105440Sjm199354 7115440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 7125440Sjm199354 713*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 714*5931Sjm199354 if ((vp = svc_file->vsf_req.vsr_vp) == NULL) 7155440Sjm199354 return (-1); 7165440Sjm199354 7175440Sjm199354 /* get the attributes */ 7185440Sjm199354 xva_init(&xvattr); /* sets AT_XVATTR */ 7195440Sjm199354 7205440Sjm199354 xvattr.xva_vattr.va_mask |= AT_SIZE; 721*5931Sjm199354 xvattr.xva_vattr.va_mask |= AT_MTIME; 7225440Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 7235440Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 7245440Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 7255440Sjm199354 7265440Sjm199354 if (VOP_GETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0) 7275440Sjm199354 return (-1); 7285440Sjm199354 7295440Sjm199354 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) { 7305440Sjm199354 cmn_err(CE_NOTE, "Virus scan request failed; " 7315440Sjm199354 "file system does not support virus scanning"); 7325440Sjm199354 return (-1); 7335440Sjm199354 } 7345440Sjm199354 735*5931Sjm199354 svc_file->vsf_size = xvattr.xva_vattr.va_size; 736*5931Sjm199354 svc_file->vsf_mtime.tv_sec = xvattr.xva_vattr.va_mtime.tv_sec; 737*5931Sjm199354 svc_file->vsf_mtime.tv_nsec = xvattr.xva_vattr.va_mtime.tv_nsec; 7385440Sjm199354 7395440Sjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED) == 0) 7405440Sjm199354 return (-1); 741*5931Sjm199354 svc_file->vsf_modified = xoap->xoa_av_modified; 7425440Sjm199354 7435440Sjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED) == 0) 7445440Sjm199354 return (-1); 745*5931Sjm199354 svc_file->vsf_quarantined = xoap->xoa_av_quarantined; 7465440Sjm199354 7475440Sjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP) != 0) { 748*5931Sjm199354 (void) memcpy(svc_file->vsf_scanstamp, 7495440Sjm199354 xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); 7505440Sjm199354 } 7515440Sjm199354 752*5931Sjm199354 DTRACE_PROBE1(vscan__getattr, vscan_file_t *, svc_file); 7535440Sjm199354 return (0); 7545440Sjm199354 } 7555440Sjm199354 7565440Sjm199354 7575440Sjm199354 /* 7585440Sjm199354 * vscan_svc_setattr 7595440Sjm199354 * 7605440Sjm199354 * Set the vscan related system attributes. 7615440Sjm199354 */ 7625440Sjm199354 static int 763*5931Sjm199354 vscan_svc_setattr(int idx, int which) 7645440Sjm199354 { 7655440Sjm199354 xvattr_t xvattr; 7665440Sjm199354 xoptattr_t *xoap = NULL; 7675440Sjm199354 vnode_t *vp; 7685440Sjm199354 int len; 769*5931Sjm199354 vscan_file_t *svc_file; 7705440Sjm199354 7715440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 7725440Sjm199354 773*5931Sjm199354 svc_file = &vscan_svc_files[idx]; 774*5931Sjm199354 if ((vp = svc_file->vsf_req.vsr_vp) == NULL) 7755440Sjm199354 return (-1); 7765440Sjm199354 7775440Sjm199354 /* update the attributes */ 7785440Sjm199354 xva_init(&xvattr); /* sets AT_XVATTR */ 7795440Sjm199354 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) 7805440Sjm199354 return (-1); 7815440Sjm199354 782*5931Sjm199354 if (which & XAT_AV_MODIFIED) { 783*5931Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 784*5931Sjm199354 xoap->xoa_av_modified = svc_file->vsf_modified; 785*5931Sjm199354 } 7865440Sjm199354 787*5931Sjm199354 if (which & XAT_AV_QUARANTINED) { 788*5931Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 789*5931Sjm199354 xoap->xoa_av_quarantined = svc_file->vsf_quarantined; 790*5931Sjm199354 } 7915440Sjm199354 792*5931Sjm199354 if (which & XAT_AV_SCANSTAMP) { 793*5931Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 794*5931Sjm199354 len = strlen(svc_file->vsf_scanstamp); 795*5931Sjm199354 (void) memcpy(xoap->xoa_av_scanstamp, 796*5931Sjm199354 svc_file->vsf_scanstamp, len); 797*5931Sjm199354 } 7985440Sjm199354 7995440Sjm199354 /* if access is denied, set mtime to invalidate client cache */ 800*5931Sjm199354 if (svc_file->vsf_access != VS_ACCESS_ALLOW) { 8015440Sjm199354 xvattr.xva_vattr.va_mask |= AT_MTIME; 8025440Sjm199354 gethrestime(&xvattr.xva_vattr.va_mtime); 8035440Sjm199354 } 8045440Sjm199354 8055440Sjm199354 if (VOP_SETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0) 8065440Sjm199354 return (-1); 8075440Sjm199354 808*5931Sjm199354 DTRACE_PROBE2(vscan__setattr, 809*5931Sjm199354 vscan_file_t *, svc_file, int, which); 810*5931Sjm199354 8115440Sjm199354 return (0); 8125440Sjm199354 } 8135440Sjm199354 8145440Sjm199354 8155440Sjm199354 /* 8165440Sjm199354 * vscan_svc_configure 8175440Sjm199354 * 8185440Sjm199354 * store configuration in vscan_svc_config 8195440Sjm199354 * set up vscan_svc_types array of pointers into 8205440Sjm199354 * vscan_svc_config.vsc_types for efficient searching 8215440Sjm199354 */ 8225440Sjm199354 int 8235440Sjm199354 vscan_svc_configure(vs_config_t *conf) 8245440Sjm199354 { 8255440Sjm199354 int count = 0; 8265440Sjm199354 char *p, *beg, *end; 8275440Sjm199354 8285440Sjm199354 mutex_enter(&vscan_svc_cfg_mutex); 8295440Sjm199354 8305440Sjm199354 vscan_svc_config = *conf; 8315440Sjm199354 8325440Sjm199354 (void) memset(vscan_svc_types, 0, sizeof (vscan_svc_types)); 8335440Sjm199354 8345440Sjm199354 beg = vscan_svc_config.vsc_types; 8355440Sjm199354 end = beg + vscan_svc_config.vsc_types_len; 8365440Sjm199354 8375440Sjm199354 for (p = beg; p < end; p += strlen(p) + 1) { 8385440Sjm199354 if (count >= VS_TYPES_MAX) { 8395440Sjm199354 mutex_exit(&vscan_svc_mutex); 8405440Sjm199354 return (-1); 8415440Sjm199354 } 8425440Sjm199354 8435440Sjm199354 vscan_svc_types[count] = p; 8445440Sjm199354 ++count; 8455440Sjm199354 } 8465440Sjm199354 8475440Sjm199354 mutex_exit(&vscan_svc_cfg_mutex); 8485440Sjm199354 return (0); 8495440Sjm199354 } 8505440Sjm199354 8515440Sjm199354 8525440Sjm199354 /* 8535440Sjm199354 * vscan_svc_exempt_file 8545440Sjm199354 * 8555440Sjm199354 * check if a file's size or type exempts it from virus scanning 8565440Sjm199354 * 8575440Sjm199354 * If the file is exempt from virus scanning, allow will be set 8585440Sjm199354 * to define whether files access should be allowed (B_TRUE) or 8595440Sjm199354 * denied (B_FALSE) 8605440Sjm199354 * 8615440Sjm199354 * Returns: 1 exempt 8625440Sjm199354 * 0 scan required 8635440Sjm199354 */ 8645440Sjm199354 static int 8655440Sjm199354 vscan_svc_exempt_file(vnode_t *vp, boolean_t *allow) 8665440Sjm199354 { 8675440Sjm199354 struct vattr attr; 8685440Sjm199354 8695440Sjm199354 ASSERT(vp != NULL); 8705440Sjm199354 ASSERT(vp->v_path != NULL); 8715440Sjm199354 8725440Sjm199354 attr.va_mask = AT_SIZE; 8735440Sjm199354 8745440Sjm199354 if (VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) { 8755440Sjm199354 *allow = B_FALSE; 8765440Sjm199354 return (0); 8775440Sjm199354 } 8785440Sjm199354 8795440Sjm199354 mutex_enter(&vscan_svc_cfg_mutex); 8805440Sjm199354 8815440Sjm199354 if (attr.va_size > vscan_svc_config.vsc_max_size) { 8825440Sjm199354 DTRACE_PROBE2(vscan__exempt__filesize, char *, 8835440Sjm199354 vp->v_path, int, *allow); 8845440Sjm199354 8855440Sjm199354 *allow = (vscan_svc_config.vsc_allow) ? B_TRUE : B_FALSE; 8865440Sjm199354 mutex_exit(&vscan_svc_cfg_mutex); 8875440Sjm199354 return (1); 8885440Sjm199354 } 8895440Sjm199354 8905440Sjm199354 if (vscan_svc_exempt_filetype(vp->v_path)) { 8915440Sjm199354 DTRACE_PROBE1(vscan__exempt__filetype, char *, vp->v_path); 8925440Sjm199354 *allow = B_TRUE; 8935440Sjm199354 mutex_exit(&vscan_svc_cfg_mutex); 8945440Sjm199354 return (1); 8955440Sjm199354 } 8965440Sjm199354 8975440Sjm199354 mutex_exit(&vscan_svc_cfg_mutex); 8985440Sjm199354 return (0); 8995440Sjm199354 } 9005440Sjm199354 9015440Sjm199354 9025440Sjm199354 /* 9035440Sjm199354 * vscan_svc_exempt_filetype 9045440Sjm199354 * 9055440Sjm199354 * Each entry in vscan_svc_types includes a rule indicator (+,-) 9065440Sjm199354 * followed by the match string for file types to which the rule 9075440Sjm199354 * applies. Look for first match of file type in vscan_svc_types 9085440Sjm199354 * and return 1 (exempt) if the indicator is '-', and 0 (not exempt) 9095440Sjm199354 * if the indicator is '+'. 9105440Sjm199354 * If vscan_svc_match_ext fails, or no match is found, return 0 9115440Sjm199354 * (not exempt) 9125440Sjm199354 * 9135440Sjm199354 * Returns 1: exempt, 0: not exempt 9145440Sjm199354 */ 9155440Sjm199354 static int 9165440Sjm199354 vscan_svc_exempt_filetype(char *filepath) 9175440Sjm199354 { 9185440Sjm199354 int i, rc, exempt = 0; 9195440Sjm199354 char *filename, *ext; 9205440Sjm199354 9215440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_cfg_mutex)); 9225440Sjm199354 9235440Sjm199354 if ((filename = strrchr(filepath, '/')) == 0) 9245440Sjm199354 filename = filepath; 9255440Sjm199354 else 9265440Sjm199354 filename++; 9275440Sjm199354 9285440Sjm199354 if ((ext = strrchr(filename, '.')) == NULL) 9295440Sjm199354 ext = ""; 9305440Sjm199354 else 9315440Sjm199354 ext++; 9325440Sjm199354 9335440Sjm199354 9345440Sjm199354 for (i = 0; i < VS_TYPES_MAX; i ++) { 9355440Sjm199354 if (vscan_svc_types[i] == 0) 9365440Sjm199354 break; 9375440Sjm199354 9385440Sjm199354 rc = vscan_svc_match_ext(vscan_svc_types[i] + 1, ext, 1); 9395440Sjm199354 if (rc == -1) 9405440Sjm199354 break; 9415440Sjm199354 if (rc > 0) { 9425440Sjm199354 DTRACE_PROBE2(vscan__type__match, char *, ext, 9435440Sjm199354 char *, vscan_svc_types[i]); 9445440Sjm199354 exempt = (vscan_svc_types[i][0] == '-'); 9455440Sjm199354 break; 9465440Sjm199354 } 9475440Sjm199354 } 9485440Sjm199354 9495440Sjm199354 return (exempt); 9505440Sjm199354 } 9515440Sjm199354 9525440Sjm199354 9535440Sjm199354 /* 9545440Sjm199354 * vscan_svc_match_ext 9555440Sjm199354 * 9565440Sjm199354 * Performs a case-insensitive match for two strings. The first string 9575440Sjm199354 * argument can contain the wildcard characters '?' and '*' 9585440Sjm199354 * 9595440Sjm199354 * Returns: 0 no match 9605440Sjm199354 * 1 match 9615440Sjm199354 * -1 recursion error 9625440Sjm199354 */ 9635440Sjm199354 static int 9645440Sjm199354 vscan_svc_match_ext(char *patn, char *str, int depth) 9655440Sjm199354 { 9665440Sjm199354 int c1, c2; 9675440Sjm199354 if (depth > VS_EXT_RECURSE_DEPTH) 9685440Sjm199354 return (-1); 9695440Sjm199354 9705440Sjm199354 for (;;) { 9715440Sjm199354 switch (*patn) { 9725440Sjm199354 case 0: 9735440Sjm199354 return (*str == 0); 9745440Sjm199354 9755440Sjm199354 case '?': 9765440Sjm199354 if (*str != 0) { 9775440Sjm199354 str++; 9785440Sjm199354 patn++; 9795440Sjm199354 continue; 9805440Sjm199354 } 9815440Sjm199354 return (0); 9825440Sjm199354 9835440Sjm199354 case '*': 9845440Sjm199354 patn++; 9855440Sjm199354 if (*patn == 0) 9865440Sjm199354 return (1); 9875440Sjm199354 9885440Sjm199354 while (*str) { 9895440Sjm199354 if (vscan_svc_match_ext(patn, str, depth + 1)) 9905440Sjm199354 return (1); 9915440Sjm199354 str++; 9925440Sjm199354 } 9935440Sjm199354 return (0); 9945440Sjm199354 9955440Sjm199354 default: 9965440Sjm199354 if (*str != *patn) { 9975440Sjm199354 c1 = *str; 9985440Sjm199354 c2 = *patn; 9995440Sjm199354 10005440Sjm199354 c1 = tolower(c1); 10015440Sjm199354 c2 = tolower(c2); 10025440Sjm199354 if (c1 != c2) 10035440Sjm199354 return (0); 10045440Sjm199354 } 10055440Sjm199354 str++; 10065440Sjm199354 patn++; 10075440Sjm199354 continue; 10085440Sjm199354 } 10095440Sjm199354 } 10105440Sjm199354 /* NOT REACHED */ 10115440Sjm199354 } 1012