1/* 2 Unix SMB/CIFS implementation. 3 SMB torture tester - mangling test 4 Copyright (C) Andrew Tridgell 2002 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23static TDB_CONTEXT *tdb; 24 25#define NAME_LENGTH 20 26 27static unsigned total, collisions, failures; 28 29static BOOL test_one(struct cli_state *cli, const char *name) 30{ 31 int fnum; 32 fstring shortname; 33 fstring name2; 34 NTSTATUS status; 35 TDB_DATA data; 36 37 total++; 38 39 fnum = cli_open(cli, name, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); 40 if (fnum == -1) { 41 printf("open of %s failed (%s)\n", name, cli_errstr(cli)); 42 return False; 43 } 44 45 if (!cli_close(cli, fnum)) { 46 printf("close of %s failed (%s)\n", name, cli_errstr(cli)); 47 return False; 48 } 49 50 /* get the short name */ 51 status = cli_qpathinfo_alt_name(cli, name, shortname); 52 if (!NT_STATUS_IS_OK(status)) { 53 printf("query altname of %s failed (%s)\n", name, cli_errstr(cli)); 54 return False; 55 } 56 57 fstr_sprintf(name2, "\\mangle_test\\%s", shortname); 58 if (!cli_unlink(cli, name2)) { 59 printf("unlink of %s (%s) failed (%s)\n", 60 name2, name, cli_errstr(cli)); 61 return False; 62 } 63 64 /* recreate by short name */ 65 fnum = cli_open(cli, name2, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); 66 if (fnum == -1) { 67 printf("open2 of %s failed (%s)\n", name2, cli_errstr(cli)); 68 return False; 69 } 70 if (!cli_close(cli, fnum)) { 71 printf("close of %s failed (%s)\n", name, cli_errstr(cli)); 72 return False; 73 } 74 75 /* and unlink by long name */ 76 if (!cli_unlink(cli, name)) { 77 printf("unlink2 of %s (%s) failed (%s)\n", 78 name, name2, cli_errstr(cli)); 79 failures++; 80 cli_unlink(cli, name2); 81 return True; 82 } 83 84 /* see if the short name is already in the tdb */ 85 data = tdb_fetch_bystring(tdb, shortname); 86 if (data.dptr) { 87 /* maybe its a duplicate long name? */ 88 if (!strequal(name, data.dptr)) { 89 /* we have a collision */ 90 collisions++; 91 printf("Collision between %s and %s -> %s " 92 " (coll/tot: %u/%u)\n", 93 name, data.dptr, shortname, collisions, total); 94 } 95 free(data.dptr); 96 } else { 97 TDB_DATA namedata; 98 /* store it for later */ 99 namedata.dptr = name; 100 namedata.dsize = strlen(name)+1; 101 tdb_store_bystring(tdb, shortname, namedata, TDB_REPLACE); 102 } 103 104 return True; 105} 106 107 108static void gen_name(char *name) 109{ 110 const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~... "; 111 unsigned max_idx = strlen(chars); 112 unsigned len; 113 int i; 114 char *p; 115 116 fstrcpy(name, "\\mangle_test\\"); 117 p = name + strlen(name); 118 119 len = 1 + random() % NAME_LENGTH; 120 121 for (i=0;i<len;i++) { 122 p[i] = chars[random() % max_idx]; 123 } 124 125 p[i] = 0; 126 127 if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) { 128 p[0] = '_'; 129 } 130 131 /* have a high probability of a common lead char */ 132 if (random() % 2 == 0) { 133 p[0] = 'A'; 134 } 135 136 /* and a medium probability of a common lead string */ 137 if (random() % 10 == 0) { 138 if (strlen(p) <= 5) { 139 fstrcpy(p, "ABCDE"); 140 } else { 141 /* try not to kill off the null termination */ 142 memcpy(p, "ABCDE", 5); 143 } 144 } 145 146 /* and a high probability of a good extension length */ 147 if (random() % 2 == 0) { 148 char *s = strrchr(p, '.'); 149 if (s) { 150 s[4] = 0; 151 } 152 } 153 154 /* ..... and a 100% proability of a file not ending in "." */ 155 if (p[strlen(p)-1] == '.') 156 p[strlen(p)-1] = '_'; 157} 158 159 160BOOL torture_mangle(int dummy) 161{ 162 extern int torture_numops; 163 static struct cli_state *cli; 164 int i; 165 BOOL ret = True; 166 167 printf("starting mangle test\n"); 168 169 if (!torture_open_connection(&cli)) { 170 return False; 171 } 172 173 /* we will use an internal tdb to store the names we have used */ 174 tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0); 175 if (!tdb) { 176 printf("ERROR: Failed to open tdb\n"); 177 return False; 178 } 179 180 cli_unlink(cli, "\\mangle_test\\*"); 181 cli_rmdir(cli, "\\mangle_test"); 182 183 if (!cli_mkdir(cli, "\\mangle_test")) { 184 printf("ERROR: Failed to make directory\n"); 185 return False; 186 } 187 188 for (i=0;i<torture_numops;i++) { 189 fstring name; 190 ZERO_STRUCT(name); 191 192 gen_name(name); 193 194 if (!test_one(cli, name)) { 195 ret = False; 196 break; 197 } 198 if (total && total % 100 == 0) { 199 printf("collisions %u/%u - %.2f%% (%u failures)\r", 200 collisions, total, (100.0*collisions) / total, failures); 201 } 202 } 203 204 cli_unlink(cli, "\\mangle_test\\*"); 205 if (!cli_rmdir(cli, "\\mangle_test")) { 206 printf("ERROR: Failed to remove directory\n"); 207 return False; 208 } 209 210 printf("\nTotal collisions %u/%u - %.2f%% (%u failures)\n", 211 collisions, total, (100.0*collisions) / total, failures); 212 213 torture_close_connection(cli); 214 215 printf("mangle test finished\n"); 216 return (ret && (failures == 0)); 217} 218