allusers.c 10.7 KB
Newer Older
rswindell's avatar
rswindell committed
1 2 3 4
/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
5
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
rswindell's avatar
rswindell committed
6 7 8 9 10 11 12 13 14 15 16 17 18
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/
19 20 21 22 23 24 25

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>

26 27
#include "sbbsdefs.h"
#include "str_util.h"
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

int  min=0,max=99;
long reqflags[4]={0},reqrest=0,reqexempt=0;

char *usage=
"\nusage: allusers [data\\user path] [[-require] [...]] "
	"/modify [[/modify] [...]]\n"
"\nwhere require is one of:\n"
"       L#                  set minimum level to # (default=0)\n"
"       M#                  set maximum level to # (default=99)\n"
"       F#<flags>           set required flags from flag set #\n"
"       E<flags>            set required exemptions\n"
"       R<flags>            set required restrictions\n"
"\nwhere modify is one of:\n"
"       L#                  change security level to #\n"
"       F#[+|-]<flags>      add or remove flags from flag set #\n"
"       E[+|-]<flags>       add or remove exemption flags\n"
"       R[+|-]<flags>       add or remove restriction flags\n"
"\nExamples:\n"
"       ALLUSERS -L30 /FA   add 'A' to flag set #1 for all level 30+ users\n"
"       ALLUSERS /F3-G      remove 'G' from flag set #3 for all users\n"
"       ALLUSERS -F2B /E-P  remove 'P' exemption for all users with FLAG '2B'\n"
deuce's avatar
deuce committed
50
"       ALLUSERS /R+W       add 'W' restriction for all users"
51 52 53 54 55 56 57 58 59 60 61 62
;

/****************************************************************************/
/* Attempts to lock a user record, retries for up to 10 seconds 			*/
/* Returns 0 on success, -1 on failure										*/
/****************************************************************************/
int lockuser(FILE *stream, ulong offset)
{
	time_t start;

	if(lock(fileno(stream),offset,U_LEN)==0)
		return(0);
rswindell's avatar
rswindell committed
63 64 65 66 67 68 69 70
	start=time(NULL);
	while(1) {
		if(lock(fileno(stream),offset,U_LEN)==0)
			return(0);
		if(time(NULL)-start>=10L)
			break; 
	}
	return(-1);
71 72 73 74 75 76 77
}

/****************************************************************************/
/* Returns bytes offset into user record for flag set # 'set'               */
/****************************************************************************/
long getflagoff(int set)
{
rswindell's avatar
rswindell committed
78 79 80 81 82 83 84 85 86 87
	switch(set) {
		default:
			return(U_FLAGS1);
		case 2:
			return(U_FLAGS2);
		case 3:
			return(U_FLAGS3);
		case 4:
			return(U_FLAGS4); 
	}
88 89 90 91 92 93 94 95 96 97 98 99
}

/****************************************************************************/
/* Checks a user record against the requirements set on the command line	*/
/* Returns 1 if the user meets the requirements (or no requirements were	*/
/* specified) or 0 if the user does not meet any of the requirements.		*/
/****************************************************************************/
int chkuser(FILE *stream, long offset)
{
	char str[128];
	int i;

rswindell's avatar
rswindell committed
100 101 102 103 104 105 106 107 108
	if(min || max!=99) {			/* Check security level */
		fseek(stream,offset+U_LEVEL,SEEK_SET);
		if(!fread(str,2,1,stream))
			return(0);
		str[2]=0;
		i=atoi(str);
		if(i<min || i>max)			/* not within range */
			return(0);				/* so skip this user */
	}
109

rswindell's avatar
rswindell committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123
	for(i=0;i<4;i++)
		if(reqflags[i]) {
			fseek(stream,offset+getflagoff(i+1),SEEK_SET);
			if(!fread(str,8,1,stream))
				return(0);
			str[8]=0;
			truncsp(str);
			if((ahtoul(str)&reqflags[i])!=reqflags[i])
				return(0); 	/* doesn't have 'em all */

		}

	if(reqrest) {
		fseek(stream,offset+U_REST,SEEK_SET);
124 125 126 127
		if(!fread(str,8,1,stream))
			return(0);
		str[8]=0;
		truncsp(str);
rswindell's avatar
rswindell committed
128 129 130
		if((ahtoul(str)&reqrest)!=reqrest)
			return(0); 
	}
131

rswindell's avatar
rswindell committed
132 133 134 135 136 137 138 139 140
	if(reqexempt) {
		fseek(stream,offset+U_REST,SEEK_SET);
		if(!fread(str,8,1,stream))
			return(0);
		str[8]=0;
		truncsp(str);
		if((ahtoul(str)&reqexempt)!=reqexempt)
			return(0); 
	}
141

rswindell's avatar
rswindell committed
142
	return(1);
143 144 145 146 147
}

int main(int argc, char **argv)
{
	char	dir[128],str[128];
rswindell's avatar
rswindell committed
148
	int 	i,j,file,set,sub,mod;
149 150
	long	l,f,flags,flagoff,offset;
	off_t	length;
151 152
	FILE	*stream;

rswindell's avatar
rswindell committed
153
	printf("\nALLUSERS v2.10 - Bulk User Editor for Synchronet User Database\n");
154

rswindell's avatar
rswindell committed
155
	if(argc<2) {
deuce's avatar
deuce committed
156
		puts(usage);
rswindell's avatar
rswindell committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
		exit(1); 
	}
	dir[0]=0;
	for(i=1;i<argc;i++) {
		flags=flagoff=sub=mod=0;
		if(argv[i][0]=='-')
			switch(toupper(argv[i][1])) {
				case 'L':                       /* Set minimum sec level */
					min=atoi(argv[i]+2);
					break;
				case 'M':                       /* Set maximum sec level */
					max=atoi(argv[i]+2);
					break;
				case 'F':                       /* Set required flags */
					j=3;
					set=1;
173
					if(IS_DIGIT(argv[i][2]))
rswindell's avatar
rswindell committed
174
						set=argv[i][2]&0xf;
175
					else
rswindell's avatar
rswindell committed
176 177
						j=2;
					for(;argv[i][j];j++)
178
						if(IS_ALPHA(argv[i][j]))
rswindell's avatar
rswindell committed
179 180 181 182
							reqflags[set-1]|=FLAG(toupper(argv[i][j]));
					break;
				case 'R':                       /* Set required restrictions */
					for(j=2;argv[i][j];j++)
183
						if(IS_ALPHA(argv[i][j]))
rswindell's avatar
rswindell committed
184 185 186 187
							reqrest|=FLAG(toupper(argv[i][j]));
					break;
				case 'E':                       /* Set required exemptions */
					for(j=2;argv[i][j];j++)
188
						if(IS_ALPHA(argv[i][j]))
rswindell's avatar
rswindell committed
189 190 191
							reqexempt|=FLAG(toupper(argv[i][j]));
					break;
				default:						/* Unrecognized include */
deuce's avatar
deuce committed
192
					puts(usage);
rswindell's avatar
rswindell committed
193 194 195 196 197 198 199 200
					exit(1); 
		}

		else if(argv[i][0]=='/')
			switch(toupper(argv[i][1])) {
				case 'F':   /* flags */
					j=3;
					set=1;
201
					if(IS_DIGIT(argv[i][2]))
rswindell's avatar
rswindell committed
202
						set=argv[i][2]&0xf;
203
					else
rswindell's avatar
rswindell committed
204 205 206 207 208 209 210 211
						j=2;
					if(argv[i][j]=='+')
						j++;
					else if(argv[i][j]=='-') {
						j++;
						sub=1; 
					}
					for(;argv[i][j];j++)
212
						if(IS_ALPHA(argv[i][j]))
rswindell's avatar
rswindell committed
213
							flags|=FLAG(toupper(argv[i][j]));
214
					SAFEPRINTF(str,"%suser.dat",dir);
rswindell's avatar
rswindell committed
215 216 217 218 219 220 221 222 223
					if(!fexistcase(str) || (file=sopen(str,O_RDWR|O_BINARY,SH_DENYNO))==-1) {
						printf("Error opening %s\n",str);
						exit(1); 
					}
					if((stream=fdopen(file,"w+b"))==NULL) {
						printf("Error opening %s\n",str);
						exit(1); 
					}
					setvbuf(stream,NULL,_IOFBF,2048);
224
					length=(ulong)filelength(file);
rswindell's avatar
rswindell committed
225 226 227 228
					printf("\n%s Flags %s Set #%d\n",sub ? "Removing":"Adding"
						,sub ? "from":"to",set);
					for(offset=0;offset<length;offset+=U_LEN) {
						printf("%lu of %lu (%u modified)\r"
229
							,(offset/U_LEN)+1,(ulong)(length/U_LEN),mod);
rswindell's avatar
rswindell committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
						if(lockuser(stream,offset)) {
							printf("Error locking offset %lu\n",offset);
							continue; 
						}
						if(!chkuser(stream,offset)) {
							unlock(fileno(stream),offset,U_LEN);
							continue; 
						}
						flagoff=getflagoff(set);
						fseek(stream,offset+flagoff,SEEK_SET);
						fread(str,8,1,stream);
						str[8]=0;
						truncsp(str);
						l=f=ahtoul(str);
						if(sub)
							l&=~flags;
						else
							l|=flags;
						if(l==f) {	/* no change */
							unlock(fileno(stream),offset,U_LEN);
							continue; 
						}
						mod++;
						sprintf(str,"%lx",l);
						while(strlen(str)<8)
							strcat(str,"\3");
						fseek(stream,offset+flagoff,SEEK_SET);
						fwrite(str,8,1,stream);
						unlock(fileno(stream),offset,U_LEN); 
					}
					fclose(stream);
					printf("\n");
					break;
			   case 'E':    /* Exemptions */
					flagoff=U_EXEMPT;
265
					// fall-through
rswindell's avatar
rswindell committed
266 267 268 269 270 271 272 273 274 275 276
			   case 'R':    /* Restrictions */
					if(!flagoff)
						flagoff=U_REST;
					j=2;
					if(argv[i][j]=='+')
						j++;
					else if(argv[i][j]=='-') {
						j++;
						sub=1; 
					}
					for(;argv[i][j];j++)
277
						if(IS_ALPHA(argv[i][j]))
rswindell's avatar
rswindell committed
278
							flags|=FLAG(toupper(argv[i][j]));
279
					SAFEPRINTF(str,"%suser.dat",dir);
rswindell's avatar
rswindell committed
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
					if(!fexistcase(str) || (file=sopen(str,O_RDWR|O_BINARY,SH_DENYNO))==-1) {
						printf("Error opening %s\n",str);
						exit(1); 
					}
					if((stream=fdopen(file,"w+b"))==NULL) {
						printf("Error opening %s\n",str);
						exit(1); 
					}
					setvbuf(stream,NULL,_IOFBF,2048);
					length=filelength(file);
					printf("\n%s %s\n"
						,sub ? "Removing":"Adding"
						,flagoff==U_REST ? "Restrictions":"Exemptions");
					for(offset=0;offset<length;offset+=U_LEN) {
						printf("%lu of %lu (%u modified)\r"
295
							,(offset/U_LEN)+1,(ulong)(length/U_LEN),mod);
rswindell's avatar
rswindell committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
						if(lockuser(stream,offset)) {
							printf("Error locking offset %lu\n",offset);
							continue; 
						}
						if(!chkuser(stream,offset)) {
							unlock(fileno(stream),offset,U_LEN);
							continue; 
						}
						fseek(stream,offset+flagoff,SEEK_SET);
						fread(str,8,1,stream);
						str[8]=0;
						truncsp(str);
						l=f=ahtoul(str);
						if(sub)
							l&=~flags;
						else
							l|=flags;
						if(l==f) {	/* no change */
							unlock(fileno(stream),offset,U_LEN);
							continue; 
						}
						mod++;
						sprintf(str,"%lx",l);
						while(strlen(str)<8)
							strcat(str,"\3");
						fseek(stream,offset+flagoff,SEEK_SET);
						fwrite(str,8,1,stream);
						unlock(fileno(stream),offset,U_LEN); 
					}
					fclose(stream);
					printf("\n");
					break;
			   case 'L':    /* Level */
					j=atoi(argv[i]+2);
					if(j>99)
						j=99;
					if(j<0)
						j=0;
334
					SAFEPRINTF(str,"%suser.dat",dir);
rswindell's avatar
rswindell committed
335 336 337 338 339 340 341 342 343 344 345 346 347
					if(!fexistcase(str) || (file=sopen(str,O_RDWR|O_BINARY,SH_DENYNO))==-1) {
						printf("Error opening %s\n",str);
						exit(1); 
					}
					if((stream=fdopen(file,"w+b"))==NULL) {
						printf("Error opening %s\n",str);
						exit(1); 
					}
					setvbuf(stream,NULL,_IOFBF,2048);
					length=filelength(file);
					printf("\nChanging Levels\n");
					for(offset=0;offset<length;offset+=U_LEN) {
						printf("%lu of %lu (%u modified)\r"
348
							,(offset/U_LEN)+1,(ulong)(length/U_LEN),mod);
rswindell's avatar
rswindell committed
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
						if(lockuser(stream,offset)) {
							printf("Error locking offset %lu\n",offset);
							continue; 
						}
						if(!chkuser(stream,offset)) {
							unlock(fileno(stream),offset,U_LEN);
							continue; 
						}
						fseek(stream,offset+U_LEVEL,SEEK_SET);
						fread(str,2,1,stream);
						str[2]=0;
						truncsp(str);
						if(atoi(str)==j) {		/* no change */
							unlock(fileno(stream),offset,U_LEN);
							continue; 
						}
						sprintf(str,"%02u",j);
						fseek(stream,offset+U_LEVEL,SEEK_SET);
						fwrite(str,2,1,stream);
368
						unlock(fileno(stream),offset,U_LEN);
rswindell's avatar
rswindell committed
369 370 371 372 373 374
						mod++; 
					}
					fclose(stream);
					printf("\n");
					break;
				default:
deuce's avatar
deuce committed
375
					puts(usage);
rswindell's avatar
rswindell committed
376 377 378
					exit(1); 
		}
		else {
379
			SAFECOPY(dir,argv[i]);
rswindell's avatar
rswindell committed
380 381 382 383
			backslash(dir); 
		} 
	}
	return(0);
384
}