15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 228670SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <smbsrv/smb_incl.h> 275331Samw #include <smbsrv/smb_fsops.h> 285331Samw #include <smbsrv/smbinfo.h> 295772Sas200622 #include <sys/nbmlock.h> 305331Samw 317961SNatalie.Li@Sun.COM static int smb_delete_check_path(smb_request_t *, boolean_t *); 327961SNatalie.Li@Sun.COM static int smb_delete_single_file(smb_request_t *, smb_error_t *); 337961SNatalie.Li@Sun.COM static int smb_delete_multiple_files(smb_request_t *, smb_error_t *); 348670SJose.Borrego@Sun.COM static int smb_delete_find_fname(smb_request_t *, smb_odir_t *); 35*10001SJoyce.McIntosh@Sun.COM static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *); 367961SNatalie.Li@Sun.COM static int smb_delete_remove_file(smb_request_t *, smb_error_t *); 377961SNatalie.Li@Sun.COM 387961SNatalie.Li@Sun.COM static void smb_delete_error(smb_error_t *, uint32_t, uint16_t, uint16_t); 395331Samw 405331Samw /* 415331Samw * smb_com_delete 425331Samw * 435331Samw * The delete file message is sent to delete a data file. The appropriate 445331Samw * Tid and additional pathname are passed. Read only files may not be 455331Samw * deleted, the read-only attribute must be reset prior to file deletion. 465331Samw * 475331Samw * NT supports a hidden permission known as File Delete Child (FDC). If 485331Samw * the user has FullControl access to a directory, the user is permitted 495331Samw * to delete any object in the directory regardless of the permissions 505331Samw * on the object. 515331Samw * 525331Samw * Client Request Description 535331Samw * ================================== ================================= 545331Samw * UCHAR WordCount; Count of parameter words = 1 555331Samw * USHORT SearchAttributes; 565331Samw * USHORT ByteCount; Count of data bytes; min = 2 575331Samw * UCHAR BufferFormat; 0x04 585331Samw * STRING FileName[]; File name 595331Samw * 605331Samw * Multiple files may be deleted in response to a single request as 615331Samw * SMB_COM_DELETE supports wildcards 625331Samw * 635331Samw * SearchAttributes indicates the attributes that the target file(s) must 645331Samw * have. If the attribute is zero then only normal files are deleted. If 655331Samw * the system file or hidden attributes are specified then the delete is 665331Samw * inclusive -both the specified type(s) of files and normal files are 675331Samw * deleted. Attributes are described in the "Attribute Encoding" section 685331Samw * of this document. 695331Samw * 705331Samw * If bit0 of the Flags2 field of the SMB header is set, a pattern is 715331Samw * passed in, and the file has a long name, then the passed pattern much 725331Samw * match the long file name for the delete to succeed. If bit0 is clear, a 735331Samw * pattern is passed in, and the file has a long name, then the passed 745331Samw * pattern must match the file's short name for the deletion to succeed. 755331Samw * 765331Samw * Server Response Description 775331Samw * ================================== ================================= 785331Samw * UCHAR WordCount; Count of parameter words = 0 795331Samw * USHORT ByteCount; Count of data bytes = 0 805331Samw * 815331Samw * 4.2.10.1 Errors 825331Samw * 835331Samw * ERRDOS/ERRbadpath 845331Samw * ERRDOS/ERRbadfile 855331Samw * ERRDOS/ERRnoaccess 865331Samw * ERRDOS/ERRbadshare # returned by NT for files that are already open 875331Samw * ERRHRD/ERRnowrite 885331Samw * ERRSRV/ERRaccess 895331Samw * ERRSRV/ERRinvdevice 905331Samw * ERRSRV/ERRinvid 915331Samw * ERRSRV/ERRbaduid 925331Samw */ 936030Sjb150015 smb_sdrc_t 946139Sjb150015 smb_pre_delete(smb_request_t *sr) 955331Samw { 966139Sjb150015 int rc; 977961SNatalie.Li@Sun.COM smb_fqi_t *fqi; 987961SNatalie.Li@Sun.COM 997961SNatalie.Li@Sun.COM fqi = &sr->arg.dirop.fqi; 1006139Sjb150015 1019343SAfshin.Ardakani@Sun.COM if ((rc = smbsr_decode_vwv(sr, "w", &fqi->fq_sattr)) == 0) 1029343SAfshin.Ardakani@Sun.COM rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path); 1036139Sjb150015 1047961SNatalie.Li@Sun.COM DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr, smb_fqi_t *, fqi); 1056139Sjb150015 1066139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1076139Sjb150015 } 1086139Sjb150015 1096139Sjb150015 void 1106139Sjb150015 smb_post_delete(smb_request_t *sr) 1116139Sjb150015 { 1126139Sjb150015 DTRACE_SMB_1(op__Delete__done, smb_request_t *, sr); 1136139Sjb150015 } 1146139Sjb150015 1157348SJose.Borrego@Sun.COM /* 1167348SJose.Borrego@Sun.COM * smb_com_delete 1177348SJose.Borrego@Sun.COM * 1187961SNatalie.Li@Sun.COM * 1. pre-process pathname - smb_delete_check_path() 1197961SNatalie.Li@Sun.COM * checks dot, bad path syntax, wildcards in path 1207348SJose.Borrego@Sun.COM * 1217961SNatalie.Li@Sun.COM * 2. process the path to get directory node & last_comp, 1227961SNatalie.Li@Sun.COM * store these in fqi 1237961SNatalie.Li@Sun.COM * - If smb_pathname_reduce cannot find the specified path, 1247961SNatalie.Li@Sun.COM * the error (ENOTDIR) is translated to NT_STATUS_OBJECT_PATH_NOT_FOUND 1257961SNatalie.Li@Sun.COM * if the target is a single file (no wildcards). If there are 1267961SNatalie.Li@Sun.COM * wildcards in the last_comp, NT_STATUS_OBJECT_NAME_NOT_FOUND is 1277961SNatalie.Li@Sun.COM * used instead. 1287961SNatalie.Li@Sun.COM * - If the directory node is the mount point and the last component 1297961SNatalie.Li@Sun.COM * is ".." NT_STATUS_OBJECT_PATH_SYNTAX_BAD is returned. 1307348SJose.Borrego@Sun.COM * 1317961SNatalie.Li@Sun.COM * 3. check access permissions 1327348SJose.Borrego@Sun.COM * 1337961SNatalie.Li@Sun.COM * 4. invoke the appropriate deletion routine to find and remove 1347961SNatalie.Li@Sun.COM * the specified file(s). 1357961SNatalie.Li@Sun.COM * - if target is a single file (no wildcards) - smb_delete_single_file 1367961SNatalie.Li@Sun.COM * - if the target contains wildcards - smb_delete_multiple_files 1377961SNatalie.Li@Sun.COM * 1387961SNatalie.Li@Sun.COM * Returns: SDRC_SUCCESS or SDRC_ERROR 1397348SJose.Borrego@Sun.COM */ 1406139Sjb150015 smb_sdrc_t 1416139Sjb150015 smb_com_delete(smb_request_t *sr) 1426139Sjb150015 { 1437348SJose.Borrego@Sun.COM int rc; 1447961SNatalie.Li@Sun.COM smb_error_t err; 1457961SNatalie.Li@Sun.COM uint32_t status; 1467348SJose.Borrego@Sun.COM boolean_t wildcards; 1477961SNatalie.Li@Sun.COM smb_fqi_t *fqi; 1485331Samw 1497961SNatalie.Li@Sun.COM fqi = &sr->arg.dirop.fqi; 1507961SNatalie.Li@Sun.COM 1517961SNatalie.Li@Sun.COM if (smb_delete_check_path(sr, &wildcards) != 0) 1526139Sjb150015 return (SDRC_ERROR); 1535772Sas200622 1549343SAfshin.Ardakani@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path, 1557961SNatalie.Li@Sun.COM sr->tid_tree->t_snode, sr->tid_tree->t_snode, 1569343SAfshin.Ardakani@Sun.COM &fqi->fq_dnode, fqi->fq_last_comp); 1577961SNatalie.Li@Sun.COM if (rc == 0) { 1589343SAfshin.Ardakani@Sun.COM if (fqi->fq_dnode->vp->v_type != VDIR) { 1599343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_dnode); 1607961SNatalie.Li@Sun.COM rc = ENOTDIR; 1617961SNatalie.Li@Sun.COM } 1627961SNatalie.Li@Sun.COM } 1637961SNatalie.Li@Sun.COM if (rc != 0) { 1647961SNatalie.Li@Sun.COM if (rc == ENOTDIR) { 1657961SNatalie.Li@Sun.COM if (wildcards) 1667961SNatalie.Li@Sun.COM status = NT_STATUS_OBJECT_NAME_NOT_FOUND; 1677961SNatalie.Li@Sun.COM else 1687961SNatalie.Li@Sun.COM status = NT_STATUS_OBJECT_PATH_NOT_FOUND; 1697961SNatalie.Li@Sun.COM smbsr_error(sr, status, ERRDOS, ERROR_FILE_NOT_FOUND); 1707961SNatalie.Li@Sun.COM } else { 1717961SNatalie.Li@Sun.COM smbsr_errno(sr, rc); 1727348SJose.Borrego@Sun.COM } 1737348SJose.Borrego@Sun.COM 1747348SJose.Borrego@Sun.COM return (SDRC_ERROR); 1757348SJose.Borrego@Sun.COM } 1767348SJose.Borrego@Sun.COM 1779343SAfshin.Ardakani@Sun.COM if ((fqi->fq_dnode == sr->tid_tree->t_snode) && 1789343SAfshin.Ardakani@Sun.COM (strcmp(fqi->fq_last_comp, "..") == 0)) { 1799343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_dnode); 1807961SNatalie.Li@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 1817961SNatalie.Li@Sun.COM ERRDOS, ERROR_BAD_PATHNAME); 1827961SNatalie.Li@Sun.COM return (SDRC_ERROR); 1837961SNatalie.Li@Sun.COM } 1847961SNatalie.Li@Sun.COM 1859343SAfshin.Ardakani@Sun.COM rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode, 1867961SNatalie.Li@Sun.COM FILE_LIST_DIRECTORY); 1877961SNatalie.Li@Sun.COM if (rc != 0) { 1889343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_dnode); 1897961SNatalie.Li@Sun.COM smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 1907961SNatalie.Li@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 1917961SNatalie.Li@Sun.COM return (SDRC_ERROR); 1927961SNatalie.Li@Sun.COM } 1937961SNatalie.Li@Sun.COM 1947961SNatalie.Li@Sun.COM if (wildcards) 1957961SNatalie.Li@Sun.COM rc = smb_delete_multiple_files(sr, &err); 1967961SNatalie.Li@Sun.COM else 1977961SNatalie.Li@Sun.COM rc = smb_delete_single_file(sr, &err); 1987961SNatalie.Li@Sun.COM 1999343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_dnode); 2008026SJoyce.McIntosh@Sun.COM 2017961SNatalie.Li@Sun.COM if (rc != 0) 2027961SNatalie.Li@Sun.COM smbsr_set_error(sr, &err); 2037961SNatalie.Li@Sun.COM else 2047961SNatalie.Li@Sun.COM rc = smbsr_encode_empty_result(sr); 2055331Samw 2067961SNatalie.Li@Sun.COM return (rc == 0 ? SDRC_SUCCESS : SDRC_ERROR); 2077961SNatalie.Li@Sun.COM } 2087961SNatalie.Li@Sun.COM 2097961SNatalie.Li@Sun.COM /* 2107961SNatalie.Li@Sun.COM * smb_delete_single_file 2117961SNatalie.Li@Sun.COM * 2127961SNatalie.Li@Sun.COM * Find the specified file and, if its attributes match the search 2137961SNatalie.Li@Sun.COM * criteria, delete it. 2147961SNatalie.Li@Sun.COM * 2157961SNatalie.Li@Sun.COM * Returns 0 - success (file deleted) 2167961SNatalie.Li@Sun.COM * -1 - error, err is populated with error details 2177961SNatalie.Li@Sun.COM */ 2187961SNatalie.Li@Sun.COM static int 2197961SNatalie.Li@Sun.COM smb_delete_single_file(smb_request_t *sr, smb_error_t *err) 2207961SNatalie.Li@Sun.COM { 2217961SNatalie.Li@Sun.COM smb_fqi_t *fqi; 2228334SJose.Borrego@Sun.COM uint32_t status; 2237961SNatalie.Li@Sun.COM 2247961SNatalie.Li@Sun.COM fqi = &sr->arg.dirop.fqi; 2257961SNatalie.Li@Sun.COM 2269343SAfshin.Ardakani@Sun.COM smb_pathname_setup(sr, &fqi->fq_path); 2279343SAfshin.Ardakani@Sun.COM status = smb_validate_object_name(&fqi->fq_path); 2288334SJose.Borrego@Sun.COM if (status != NT_STATUS_SUCCESS) { 2298334SJose.Borrego@Sun.COM smb_delete_error(err, status, ERRDOS, ERROR_INVALID_NAME); 2308334SJose.Borrego@Sun.COM return (-1); 2318334SJose.Borrego@Sun.COM } 2328334SJose.Borrego@Sun.COM 2337961SNatalie.Li@Sun.COM if (smb_fsop_lookup_name(sr, sr->user_cr, 0, sr->tid_tree->t_snode, 234*10001SJoyce.McIntosh@Sun.COM fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode) != 0) { 2357961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND, 2367961SNatalie.Li@Sun.COM ERRDOS, ERROR_FILE_NOT_FOUND); 2377961SNatalie.Li@Sun.COM return (-1); 2387961SNatalie.Li@Sun.COM } 2395331Samw 240*10001SJoyce.McIntosh@Sun.COM if (smb_delete_check_dosattr(sr, err) != 0) { 2419343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_fnode); 2427961SNatalie.Li@Sun.COM return (-1); 2437961SNatalie.Li@Sun.COM } 2447961SNatalie.Li@Sun.COM 2457961SNatalie.Li@Sun.COM if (smb_delete_remove_file(sr, err) != 0) { 2469343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_fnode); 2477961SNatalie.Li@Sun.COM return (-1); 2487961SNatalie.Li@Sun.COM } 2497961SNatalie.Li@Sun.COM 2509343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_fnode); 2517961SNatalie.Li@Sun.COM return (0); 2527961SNatalie.Li@Sun.COM } 2537961SNatalie.Li@Sun.COM 2547961SNatalie.Li@Sun.COM /* 2557961SNatalie.Li@Sun.COM * smb_delete_multiple_files 2567961SNatalie.Li@Sun.COM * 2578670SJose.Borrego@Sun.COM * For each matching file found by smb_delete_find_fname: 2587961SNatalie.Li@Sun.COM * 1. lookup file 2597961SNatalie.Li@Sun.COM * 2. check the file's attributes 2607961SNatalie.Li@Sun.COM * - The search ends with an error if a readonly file 2617961SNatalie.Li@Sun.COM * (NT_STATUS_CANNOT_DELETE) is matched. 2627961SNatalie.Li@Sun.COM * - The search ends (but not an error) if a directory is 2637961SNatalie.Li@Sun.COM * matched and the request's search did not include 2647961SNatalie.Li@Sun.COM * directories. 265*10001SJoyce.McIntosh@Sun.COM * - Otherwise, if smb_delete_check_dosattr fails the file 2667961SNatalie.Li@Sun.COM * is skipped and the search continues (at step 1) 2677961SNatalie.Li@Sun.COM * 3. delete the file 2687961SNatalie.Li@Sun.COM * 2697961SNatalie.Li@Sun.COM * Returns 0 - success 2707961SNatalie.Li@Sun.COM * -1 - error, err is populated with error details 2717961SNatalie.Li@Sun.COM */ 2727961SNatalie.Li@Sun.COM static int 2737961SNatalie.Li@Sun.COM smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err) 2747961SNatalie.Li@Sun.COM { 2757961SNatalie.Li@Sun.COM int rc, deleted = 0; 2767961SNatalie.Li@Sun.COM smb_fqi_t *fqi; 2778670SJose.Borrego@Sun.COM uint16_t odid; 2788670SJose.Borrego@Sun.COM smb_odir_t *od; 2797961SNatalie.Li@Sun.COM 2807961SNatalie.Li@Sun.COM fqi = &sr->arg.dirop.fqi; 2817961SNatalie.Li@Sun.COM 2828670SJose.Borrego@Sun.COM /* 2838670SJose.Borrego@Sun.COM * Specify all search attributes (SMB_SEARCH_ATTRIBUTES) so that 284*10001SJoyce.McIntosh@Sun.COM * delete-specific checking can be done (smb_delete_check_dosattr). 2858670SJose.Borrego@Sun.COM */ 2869343SAfshin.Ardakani@Sun.COM odid = smb_odir_open(sr, fqi->fq_path.pn_path, 2879343SAfshin.Ardakani@Sun.COM SMB_SEARCH_ATTRIBUTES, 0); 2889343SAfshin.Ardakani@Sun.COM if (odid == 0) 2898670SJose.Borrego@Sun.COM return (-1); 2909343SAfshin.Ardakani@Sun.COM 2918670SJose.Borrego@Sun.COM if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) 2928670SJose.Borrego@Sun.COM return (-1); 2938670SJose.Borrego@Sun.COM 2947961SNatalie.Li@Sun.COM for (;;) { 2958670SJose.Borrego@Sun.COM rc = smb_delete_find_fname(sr, od); 2967961SNatalie.Li@Sun.COM if (rc != 0) 2977961SNatalie.Li@Sun.COM break; 2987961SNatalie.Li@Sun.COM 2997961SNatalie.Li@Sun.COM rc = smb_fsop_lookup_name(sr, sr->user_cr, 0, 3009343SAfshin.Ardakani@Sun.COM sr->tid_tree->t_snode, fqi->fq_dnode, 301*10001SJoyce.McIntosh@Sun.COM fqi->fq_od_name, &fqi->fq_fnode); 3027961SNatalie.Li@Sun.COM if (rc != 0) 3037961SNatalie.Li@Sun.COM break; 3047961SNatalie.Li@Sun.COM 305*10001SJoyce.McIntosh@Sun.COM if (smb_delete_check_dosattr(sr, err) != 0) { 3069343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_fnode); 3077961SNatalie.Li@Sun.COM if (err->status == NT_STATUS_CANNOT_DELETE) { 3089635SJoyce.McIntosh@Sun.COM smb_odir_close(od); 3098670SJose.Borrego@Sun.COM smb_odir_release(od); 3107961SNatalie.Li@Sun.COM return (-1); 3117348SJose.Borrego@Sun.COM } 3127961SNatalie.Li@Sun.COM if ((err->status == NT_STATUS_FILE_IS_A_DIRECTORY) && 3139343SAfshin.Ardakani@Sun.COM (SMB_SEARCH_DIRECTORY(fqi->fq_sattr) != 0)) 3147961SNatalie.Li@Sun.COM break; 3157961SNatalie.Li@Sun.COM continue; 3165772Sas200622 } 3175772Sas200622 3187961SNatalie.Li@Sun.COM if (smb_delete_remove_file(sr, err) == 0) { 3197961SNatalie.Li@Sun.COM ++deleted; 3209343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_fnode); 3217961SNatalie.Li@Sun.COM continue; 3227961SNatalie.Li@Sun.COM } 3237961SNatalie.Li@Sun.COM if (err->status == NT_STATUS_OBJECT_NAME_NOT_FOUND) { 3249343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_fnode); 3257961SNatalie.Li@Sun.COM continue; 3265331Samw } 3275331Samw 3289635SJoyce.McIntosh@Sun.COM smb_odir_close(od); 3298670SJose.Borrego@Sun.COM smb_odir_release(od); 3309343SAfshin.Ardakani@Sun.COM smb_node_release(fqi->fq_fnode); 3317961SNatalie.Li@Sun.COM return (-1); 3325331Samw } 3335331Samw 3349635SJoyce.McIntosh@Sun.COM smb_odir_close(od); 3358670SJose.Borrego@Sun.COM smb_odir_release(od); 3367961SNatalie.Li@Sun.COM 3375331Samw if ((rc != 0) && (rc != ENOENT)) { 3387961SNatalie.Li@Sun.COM smbsr_map_errno(rc, err); 3397961SNatalie.Li@Sun.COM return (-1); 3405331Samw } 3415331Samw 3425331Samw if (deleted == 0) { 3437961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_NO_SUCH_FILE, 3447961SNatalie.Li@Sun.COM ERRDOS, ERROR_FILE_NOT_FOUND); 3457961SNatalie.Li@Sun.COM return (-1); 3467961SNatalie.Li@Sun.COM } 3477961SNatalie.Li@Sun.COM 3487961SNatalie.Li@Sun.COM return (0); 3497961SNatalie.Li@Sun.COM } 3507961SNatalie.Li@Sun.COM 3517961SNatalie.Li@Sun.COM /* 3527961SNatalie.Li@Sun.COM * smb_delete_find_fname 3537961SNatalie.Li@Sun.COM * 3549343SAfshin.Ardakani@Sun.COM * Find next filename that matches search pattern (fqi->fq_last_comp) 3559343SAfshin.Ardakani@Sun.COM * and save it in fqi->fq_od_name. 3567961SNatalie.Li@Sun.COM * 3578670SJose.Borrego@Sun.COM * Case insensitivity note: 3588670SJose.Borrego@Sun.COM * If the tree is case insensitive and there's a case conflict 3598670SJose.Borrego@Sun.COM * with the name returned from smb_odir_read, smb_delete_find_fname 3608670SJose.Borrego@Sun.COM * performs case conflict name mangling to produce a unique filename. 3618670SJose.Borrego@Sun.COM * This ensures that any subsequent smb_fsop_lookup, (which will 3628670SJose.Borrego@Sun.COM * find the first case insensitive match) will find the correct file. 3638670SJose.Borrego@Sun.COM * 3647961SNatalie.Li@Sun.COM * Returns: 0 - success 3657961SNatalie.Li@Sun.COM * errno 3667961SNatalie.Li@Sun.COM */ 3677961SNatalie.Li@Sun.COM static int 3688670SJose.Borrego@Sun.COM smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od) 3697961SNatalie.Li@Sun.COM { 3708670SJose.Borrego@Sun.COM int rc; 3718670SJose.Borrego@Sun.COM smb_odirent_t *odirent; 3728670SJose.Borrego@Sun.COM boolean_t eos; 3738670SJose.Borrego@Sun.COM char *name; 3748670SJose.Borrego@Sun.COM char shortname[SMB_SHORTNAMELEN]; 3758670SJose.Borrego@Sun.COM char name83[SMB_SHORTNAMELEN]; 3768670SJose.Borrego@Sun.COM smb_fqi_t *fqi; 3777961SNatalie.Li@Sun.COM 3787961SNatalie.Li@Sun.COM fqi = &sr->arg.dirop.fqi; 3798670SJose.Borrego@Sun.COM odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 3807961SNatalie.Li@Sun.COM 3818670SJose.Borrego@Sun.COM rc = smb_odir_read(sr, od, odirent, &eos); 3828670SJose.Borrego@Sun.COM if (rc != 0) { 3838670SJose.Borrego@Sun.COM kmem_free(odirent, sizeof (smb_odirent_t)); 3848670SJose.Borrego@Sun.COM return (rc); 3858670SJose.Borrego@Sun.COM } 3868670SJose.Borrego@Sun.COM if (eos) { 3878670SJose.Borrego@Sun.COM kmem_free(odirent, sizeof (smb_odirent_t)); 3888670SJose.Borrego@Sun.COM return (ENOENT); 3898670SJose.Borrego@Sun.COM } 3907961SNatalie.Li@Sun.COM 3918670SJose.Borrego@Sun.COM /* if case conflict, force mangle and use shortname */ 3929231SAfshin.Ardakani@Sun.COM if ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) && 3939231SAfshin.Ardakani@Sun.COM (odirent->od_eflags & ED_CASE_CONFLICT)) { 3948670SJose.Borrego@Sun.COM (void) smb_mangle_name(odirent->od_ino, odirent->od_name, 3958670SJose.Borrego@Sun.COM shortname, name83, 1); 3968670SJose.Borrego@Sun.COM name = shortname; 3978670SJose.Borrego@Sun.COM } else { 3988670SJose.Borrego@Sun.COM name = odirent->od_name; 3998670SJose.Borrego@Sun.COM } 4009343SAfshin.Ardakani@Sun.COM (void) strlcpy(fqi->fq_od_name, name, sizeof (fqi->fq_od_name)); 4017961SNatalie.Li@Sun.COM 4028670SJose.Borrego@Sun.COM kmem_free(odirent, sizeof (smb_odirent_t)); 4038670SJose.Borrego@Sun.COM return (0); 4047961SNatalie.Li@Sun.COM } 4057961SNatalie.Li@Sun.COM 4067961SNatalie.Li@Sun.COM /* 407*10001SJoyce.McIntosh@Sun.COM * smb_delete_check_dosattr 4087961SNatalie.Li@Sun.COM * 4097961SNatalie.Li@Sun.COM * Check file's dos atributes to ensure that 4107961SNatalie.Li@Sun.COM * 1. the file is not a directory - NT_STATUS_FILE_IS_A_DIRECTORY 4117961SNatalie.Li@Sun.COM * 2. the file is not readonly - NT_STATUS_CANNOT_DELETE 4127961SNatalie.Li@Sun.COM * 3. the file's dos attributes comply with the specified search attributes 4137961SNatalie.Li@Sun.COM * If the file is either hidden or system and those attributes 4147961SNatalie.Li@Sun.COM * are not specified in the search attributes - NT_STATUS_NO_SUCH_FILE 4157961SNatalie.Li@Sun.COM * 4167961SNatalie.Li@Sun.COM * Returns: 0 - file's attributes pass all checks 4177961SNatalie.Li@Sun.COM * -1 - err populated with error details 4187961SNatalie.Li@Sun.COM */ 4197961SNatalie.Li@Sun.COM static int 420*10001SJoyce.McIntosh@Sun.COM smb_delete_check_dosattr(smb_request_t *sr, smb_error_t *err) 4217961SNatalie.Li@Sun.COM { 4227961SNatalie.Li@Sun.COM smb_fqi_t *fqi; 4237961SNatalie.Li@Sun.COM smb_node_t *node; 424*10001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 425*10001SJoyce.McIntosh@Sun.COM uint16_t sattr; 4267961SNatalie.Li@Sun.COM 4277961SNatalie.Li@Sun.COM fqi = &sr->arg.dirop.fqi; 4289343SAfshin.Ardakani@Sun.COM sattr = fqi->fq_sattr; 4299343SAfshin.Ardakani@Sun.COM node = fqi->fq_fnode; 4307961SNatalie.Li@Sun.COM 431*10001SJoyce.McIntosh@Sun.COM if (smb_node_getattr(sr, node, &attr) != 0) { 432*10001SJoyce.McIntosh@Sun.COM smb_delete_error(err, NT_STATUS_INTERNAL_ERROR, 433*10001SJoyce.McIntosh@Sun.COM ERRDOS, ERROR_INTERNAL_ERROR); 434*10001SJoyce.McIntosh@Sun.COM return (-1); 435*10001SJoyce.McIntosh@Sun.COM } 436*10001SJoyce.McIntosh@Sun.COM 437*10001SJoyce.McIntosh@Sun.COM if (attr.sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) { 4387961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_FILE_IS_A_DIRECTORY, 4397961SNatalie.Li@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 4407961SNatalie.Li@Sun.COM return (-1); 4415331Samw } 4425331Samw 4437961SNatalie.Li@Sun.COM if (SMB_PATHFILE_IS_READONLY(sr, node)) { 4447961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_CANNOT_DELETE, 4457961SNatalie.Li@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 4467961SNatalie.Li@Sun.COM return (-1); 4477961SNatalie.Li@Sun.COM } 4486030Sjb150015 449*10001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) && 450*10001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_HIDDEN(sattr))) { 4517961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_NO_SUCH_FILE, 4527961SNatalie.Li@Sun.COM ERRDOS, ERROR_FILE_NOT_FOUND); 4537961SNatalie.Li@Sun.COM return (-1); 4547961SNatalie.Li@Sun.COM } 4557961SNatalie.Li@Sun.COM 456*10001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) && 457*10001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_SYSTEM(sattr))) { 4587961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_NO_SUCH_FILE, 4597961SNatalie.Li@Sun.COM ERRDOS, ERROR_FILE_NOT_FOUND); 4607961SNatalie.Li@Sun.COM return (-1); 4617961SNatalie.Li@Sun.COM } 4627961SNatalie.Li@Sun.COM 4637961SNatalie.Li@Sun.COM return (0); 4647961SNatalie.Li@Sun.COM } 4655331Samw 4667961SNatalie.Li@Sun.COM /* 4677961SNatalie.Li@Sun.COM * smb_delete_remove_file 4687961SNatalie.Li@Sun.COM * 4697961SNatalie.Li@Sun.COM * For consistency with Windows 2000, the range check should be done 4707961SNatalie.Li@Sun.COM * after checking for sharing violations. Attempting to delete a 4717961SNatalie.Li@Sun.COM * locked file will result in sharing violation, which is the same 4727961SNatalie.Li@Sun.COM * thing that will happen if you try to delete a non-locked open file. 4737961SNatalie.Li@Sun.COM * 4747961SNatalie.Li@Sun.COM * Note that windows 2000 rejects lock requests on open files that 4757961SNatalie.Li@Sun.COM * have been opened with metadata open modes. The error is 4767961SNatalie.Li@Sun.COM * STATUS_ACCESS_DENIED. 4777961SNatalie.Li@Sun.COM * 4787961SNatalie.Li@Sun.COM * NT does not always close a file immediately, which can cause the 4797961SNatalie.Li@Sun.COM * share and access checking to fail (the node refcnt is greater 4807961SNatalie.Li@Sun.COM * than one), and the file doesn't get deleted. Breaking the oplock 4817961SNatalie.Li@Sun.COM * before share and access checking gives the client a chance to 4827961SNatalie.Li@Sun.COM * close the file. 4837961SNatalie.Li@Sun.COM * 4847961SNatalie.Li@Sun.COM * Returns: 0 - success 4857961SNatalie.Li@Sun.COM * -1 - error, err populated with error details 4867961SNatalie.Li@Sun.COM */ 4877961SNatalie.Li@Sun.COM static int 4887961SNatalie.Li@Sun.COM smb_delete_remove_file(smb_request_t *sr, smb_error_t *err) 4897961SNatalie.Li@Sun.COM { 4907961SNatalie.Li@Sun.COM int rc; 4917961SNatalie.Li@Sun.COM uint32_t status; 4927961SNatalie.Li@Sun.COM smb_fqi_t *fqi; 4937961SNatalie.Li@Sun.COM smb_node_t *node; 4949231SAfshin.Ardakani@Sun.COM uint32_t flags = 0; 4957961SNatalie.Li@Sun.COM 4967961SNatalie.Li@Sun.COM fqi = &sr->arg.dirop.fqi; 4979343SAfshin.Ardakani@Sun.COM node = fqi->fq_fnode; 4987961SNatalie.Li@Sun.COM 4999021Samw@Sun.COM (void) smb_oplock_break(node, sr->session, B_FALSE); 5007961SNatalie.Li@Sun.COM 5017961SNatalie.Li@Sun.COM smb_node_start_crit(node, RW_READER); 5027961SNatalie.Li@Sun.COM 5037961SNatalie.Li@Sun.COM status = smb_node_delete_check(node); 5047961SNatalie.Li@Sun.COM if (status != NT_STATUS_SUCCESS) { 5057961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_SHARING_VIOLATION, 5067961SNatalie.Li@Sun.COM ERRDOS, ERROR_SHARING_VIOLATION); 5077961SNatalie.Li@Sun.COM smb_node_end_crit(node); 5087961SNatalie.Li@Sun.COM return (-1); 5097961SNatalie.Li@Sun.COM } 5107961SNatalie.Li@Sun.COM 5117961SNatalie.Li@Sun.COM status = smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE); 5127961SNatalie.Li@Sun.COM if (status != NT_STATUS_SUCCESS) { 5137961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_ACCESS_DENIED, 5147961SNatalie.Li@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 5157961SNatalie.Li@Sun.COM smb_node_end_crit(node); 5167961SNatalie.Li@Sun.COM return (-1); 5177961SNatalie.Li@Sun.COM } 5187961SNatalie.Li@Sun.COM 5199231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 5209231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 5219231SAfshin.Ardakani@Sun.COM 5227961SNatalie.Li@Sun.COM rc = smb_fsop_remove(sr, sr->user_cr, node->dir_snode, 5239231SAfshin.Ardakani@Sun.COM node->od_name, flags); 5247961SNatalie.Li@Sun.COM if (rc != 0) { 5257961SNatalie.Li@Sun.COM if (rc == ENOENT) 5267961SNatalie.Li@Sun.COM smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND, 5277961SNatalie.Li@Sun.COM ERRDOS, ERROR_FILE_NOT_FOUND); 5287961SNatalie.Li@Sun.COM else 5297961SNatalie.Li@Sun.COM smbsr_map_errno(rc, err); 5307961SNatalie.Li@Sun.COM 5317961SNatalie.Li@Sun.COM smb_node_end_crit(node); 5327961SNatalie.Li@Sun.COM return (-1); 5337961SNatalie.Li@Sun.COM } 5347961SNatalie.Li@Sun.COM 5357961SNatalie.Li@Sun.COM smb_node_end_crit(node); 5367961SNatalie.Li@Sun.COM return (0); 5375331Samw } 5385331Samw 5397961SNatalie.Li@Sun.COM 5406139Sjb150015 /* 5417348SJose.Borrego@Sun.COM * smb_delete_check_path 5427348SJose.Borrego@Sun.COM * 5437961SNatalie.Li@Sun.COM * Perform initial validation on the pathname and last_comp. 5447348SJose.Borrego@Sun.COM * 5457961SNatalie.Li@Sun.COM * wildcards in path: 5467961SNatalie.Li@Sun.COM * Wildcards in the path (excluding the last_comp) should result 5477961SNatalie.Li@Sun.COM * in NT_STATUS_OBJECT_NAME_INVALID. 5487348SJose.Borrego@Sun.COM * 5497348SJose.Borrego@Sun.COM * bad path syntax: 5507348SJose.Borrego@Sun.COM * On unix .. at the root of a file system links to the root. Thus 5517348SJose.Borrego@Sun.COM * an attempt to lookup "/../../.." will be the same as looking up "/" 5527348SJose.Borrego@Sun.COM * CIFs clients expect the above to result in 5537348SJose.Borrego@Sun.COM * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible 5547348SJose.Borrego@Sun.COM * (and questionable if it's desirable) to deal with all cases 5557348SJose.Borrego@Sun.COM * but paths beginning with \\.. are handled. See bad_paths[]. 5567961SNatalie.Li@Sun.COM * Cases like "\\dir\\..\\.." will be caught and handled after the 5577961SNatalie.Li@Sun.COM * pnreduce. Cases like "\\dir\\..\\..\\filename" will still result 5587961SNatalie.Li@Sun.COM * in "\\filename" which is contrary to windows behavior. 5597348SJose.Borrego@Sun.COM * 5607961SNatalie.Li@Sun.COM * dot: 5617961SNatalie.Li@Sun.COM * A filename of '.' should result in NT_STATUS_OBJECT_NAME_INVALID 5627961SNatalie.Li@Sun.COM * Any wildcard filename that resolves to '.' should result in 5637961SNatalie.Li@Sun.COM * NT_STATUS_OBJECT_NAME_INVALID if the search attributes include 5647961SNatalie.Li@Sun.COM * FILE_ATTRIBUTE_DIRECTORY 5657348SJose.Borrego@Sun.COM * 5667348SJose.Borrego@Sun.COM * Returns: 5677961SNatalie.Li@Sun.COM * 0: path is valid. Sets *wildcard to TRUE if wildcard delete 5687348SJose.Borrego@Sun.COM * i.e. if wildcards in last component 5697961SNatalie.Li@Sun.COM * -1: path is invalid. Sets error information in sr. 5707348SJose.Borrego@Sun.COM */ 5717961SNatalie.Li@Sun.COM static int 5727348SJose.Borrego@Sun.COM smb_delete_check_path(smb_request_t *sr, boolean_t *wildcard) 5737348SJose.Borrego@Sun.COM { 5747961SNatalie.Li@Sun.COM smb_fqi_t *fqi = &sr->arg.dirop.fqi; 5757961SNatalie.Li@Sun.COM char *p, *last_comp; 5767348SJose.Borrego@Sun.COM int i, wildcards; 5779343SAfshin.Ardakani@Sun.COM smb_pathname_t *pn = &fqi->fq_path; 5787348SJose.Borrego@Sun.COM 5797348SJose.Borrego@Sun.COM struct { 5807348SJose.Borrego@Sun.COM char *name; 5817348SJose.Borrego@Sun.COM int len; 5827348SJose.Borrego@Sun.COM } *bad, bad_paths[] = { 5837348SJose.Borrego@Sun.COM {"\\..\0", 4}, 5847348SJose.Borrego@Sun.COM {"\\..\\", 4}, 5857348SJose.Borrego@Sun.COM {"..\0", 3}, 5867348SJose.Borrego@Sun.COM {"..\\", 3} 5877348SJose.Borrego@Sun.COM }; 5887348SJose.Borrego@Sun.COM 5897348SJose.Borrego@Sun.COM /* find last component, strip trailing '\\' */ 5909343SAfshin.Ardakani@Sun.COM p = pn->pn_path + strlen(pn->pn_path) - 1; 5917348SJose.Borrego@Sun.COM while (*p == '\\') { 5927348SJose.Borrego@Sun.COM *p = '\0'; 5937348SJose.Borrego@Sun.COM --p; 5947348SJose.Borrego@Sun.COM } 5958938Samw@Sun.COM 5969343SAfshin.Ardakani@Sun.COM if ((p = strrchr(pn->pn_path, '\\')) == NULL) 5979343SAfshin.Ardakani@Sun.COM last_comp = pn->pn_path; 5988938Samw@Sun.COM else 5997961SNatalie.Li@Sun.COM last_comp = ++p; 6007348SJose.Borrego@Sun.COM 6018938Samw@Sun.COM wildcards = smb_convert_wildcards(last_comp); 6028938Samw@Sun.COM 6039343SAfshin.Ardakani@Sun.COM if (last_comp != pn->pn_path) { 6048938Samw@Sun.COM /* 6058938Samw@Sun.COM * Wildcards are only allowed in the last component. 6068938Samw@Sun.COM * Check for additional wildcards in the path. 6078938Samw@Sun.COM */ 6089343SAfshin.Ardakani@Sun.COM if (smb_convert_wildcards(pn->pn_path) != wildcards) { 6097348SJose.Borrego@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 6107348SJose.Borrego@Sun.COM ERRDOS, ERROR_INVALID_NAME); 6117961SNatalie.Li@Sun.COM return (-1); 6127348SJose.Borrego@Sun.COM } 6137348SJose.Borrego@Sun.COM } 6147348SJose.Borrego@Sun.COM 6157961SNatalie.Li@Sun.COM /* path above the mount point */ 6167348SJose.Borrego@Sun.COM for (i = 0; i < sizeof (bad_paths) / sizeof (bad_paths[0]); ++i) { 6177348SJose.Borrego@Sun.COM bad = &bad_paths[i]; 6189343SAfshin.Ardakani@Sun.COM if (strncmp(pn->pn_path, bad->name, bad->len) == 0) { 6197348SJose.Borrego@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 6207348SJose.Borrego@Sun.COM ERRDOS, ERROR_BAD_PATHNAME); 6217961SNatalie.Li@Sun.COM return (-1); 6227348SJose.Borrego@Sun.COM } 6237348SJose.Borrego@Sun.COM } 6247348SJose.Borrego@Sun.COM 6257961SNatalie.Li@Sun.COM /* last component is, or resolves to, '.' (dot) */ 6267961SNatalie.Li@Sun.COM if ((strcmp(last_comp, ".") == 0) || 6279343SAfshin.Ardakani@Sun.COM (SMB_SEARCH_DIRECTORY(fqi->fq_sattr) && 6287961SNatalie.Li@Sun.COM (smb_match(last_comp, ".")))) { 6297348SJose.Borrego@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 6307348SJose.Borrego@Sun.COM ERRDOS, ERROR_INVALID_NAME); 6317961SNatalie.Li@Sun.COM return (-1); 6327348SJose.Borrego@Sun.COM } 6337348SJose.Borrego@Sun.COM 6347348SJose.Borrego@Sun.COM *wildcard = (wildcards != 0); 6357961SNatalie.Li@Sun.COM return (0); 6367348SJose.Borrego@Sun.COM } 6377348SJose.Borrego@Sun.COM 6387348SJose.Borrego@Sun.COM /* 6397961SNatalie.Li@Sun.COM * smb_delete_error 6406139Sjb150015 */ 6417961SNatalie.Li@Sun.COM static void 6427961SNatalie.Li@Sun.COM smb_delete_error(smb_error_t *err, 6437961SNatalie.Li@Sun.COM uint32_t status, uint16_t errcls, uint16_t errcode) 6445331Samw { 6457961SNatalie.Li@Sun.COM err->severity = ERROR_SEVERITY_ERROR; 6467961SNatalie.Li@Sun.COM err->status = status; 6477961SNatalie.Li@Sun.COM err->errcls = errcls; 6487961SNatalie.Li@Sun.COM err->errcode = errcode; 6495331Samw } 650