/* * bindedit.c -- extract info from and write info to the NetWare bindery * * v1.0 93.10.12 by Curt Sampson * Copyright 1993 by Fluor Daniel, Inc. * * Returns 2 for argument error, 1 for other error. * See the manual page for complete info. * * Define WRITE_DISABLED to make a version in which the -w option will * not work. (I suggest you then name it bindread.) * * This program is free software; you may redistribute it and/or * modify it under the terms of the GNU General Public Licence * as published by the Free Software Foundation; either version 1 * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; with even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. * * This program was compiled under Borland's Turbo C++ 3.00 with the * Novell NetWare C Interface--DOS libraries. If you make changes to * this program, please send me a copy. If they seem relevant to the * community at large, I'll integrate them into the standard release. * * Curt Sampson email: a09878@giant.rsoft.bc.ca * Fluor Daniel * 1444 Alberni Street Tel: 604 691 5458 * Vancouver, B.C. CANADA Fax: 604 687 6130 * V6G 2Z4 * * Revision History: * 93.10.12 cjs Initial version. * 93.10.14 cjs Added #define to remove write capability * 93.10.28 cjs 1.0 release. Anything below this line makes it a modified * version. * --------------------------------------------------------- */ char id[]="@(#)bindedit.c " #ifdef WRITE_DISABLED "(bindery writes disabled) " #endif "v1.0 93.10.14 by Curt Sampson (FD Vancouver)"; char copyright[]="Copyright 1993 by Fluor Daniel, Inc."; /* * this is the minimum length of a printable string in property item data * for the program to print it out as ASCII in quotes rather than as hex */ #define MIN_STR_LEN 5 #include #include #include #include /* * new types, etc. */ /* * propflags bits: * 0 = output static properties * 1 = output dynamic properties * 2 = output set properties * 3 = output item properties */ #define PROP_STATIC 1 #define PROP_DYNAMIC 2 #define PROP_SET 4 #define PROP_ITEM 8 typedef struct { unsigned char propflags; short int type[1024]; } typelist; /* * globals */ int gCheckMode = 1; /* true if we are running a check instead */ /* of an actual bindery write */ int gLineNo = 0; /* current line number of input file */ /* * bindCallErr -- given a return value from a bindery API call, it will * print an appropriate error message and return -1 if * the return value indicated an error, or stay silent and * return 0 otherwise. Line is the line no. of the error. */ int BindCallErr(int retval) { char *s; /* else print the appropriate message */ switch ( retval ) { case 0 : return 0; case 150 : s = "server out of memory"; break; case 232 : s = "write property to group"; break; case 233 : s = "member already exists"; break; case 234 : s = "no such member"; break; case 235 : s = "not group property"; break; case 236 : s = "no such set"; break; case 237 : s = "property already exists"; break; case 238 : s = "object already exists"; break; case 239 : s = "invalid name"; break; case 240 : s = "wild card not allowed"; break; case 241 : s = "invalid bindery security"; break; case 242 : s = "no object read privilege"; break; case 244 : s = "no object delete privilege"; break; case 245 : s = "no object create privilege"; break; case 246 : s = "no property delete privilege"; break; case 247 : s = "no property create privilege"; break; case 248 : s = "no property write provilege"; break; case 251 : s = "no such property"; break; case 252 : s = "no such object"; break; case 254 : s = "server bindery locked"; break; case 255 : s = "bindery failure"; break; default : s = "unknown error"; break; } fprintf(stderr, "bindedit: bindery error on line %d: %s\n", gLineNo, s); return -1; } /* * checkObjType - check to see if an object has the right type & properties */ int checkObjType(typelist *tlp, char objectFlag, WORD type) { int i = 0; /* first check to see if the flags are ok */ if ( (! (objectFlag & BF_DYNAMIC)) && (tlp->propflags & PROP_STATIC) ) i++; if ( (objectFlag & BF_DYNAMIC) && (tlp->propflags & PROP_DYNAMIC) ) i++; if ( ! i ) return 0; /* now check to see if we permit any type or only specific ones */ if ( tlp->type[0] == -1 ) /* wildcard */ return 1; /* check to see if type is in list of types to be included */ i = 0; while ( tlp->type[i] != -1 ) if ( type == tlp->type[i++] ) return 1; return 0; } /* * checkPropType - check to see if an property has the right flags */ int checkPropType(typelist *tlp, char propFlag) { int i; i = 0; if ( (! (propFlag & BF_DYNAMIC)) && (tlp->propflags & PROP_STATIC) ) i++; if ( (propFlag & BF_DYNAMIC) && (tlp->propflags & PROP_DYNAMIC) ) i++; if ( ! i ) return 0; i = 0; if ( (! (propFlag & BF_ITEM)) && (tlp->propflags & PROP_ITEM) ) i++; if ( (propFlag & BF_SET) && (tlp->propflags & PROP_SET) ) i++; if ( ! i ) return 0; return 1; } /* * printDataSeg -- print out a data segment on file f as ASCII if possible, * hex if not. If is notrim is true it will print trailing 0s. */ void printDataSeg(FILE *f, unsigned char *value, int notrim) { int ispr, len; /* is it printable? , length of data */ int i, j; /* determine length of data */ if ( notrim ) { len = 128; /* more segs, print this entire one */ } else { for ( len = 128; len > 0; len-- ) if ( value[len-1] ) break; } /* now print it */ for ( ispr=0, i=0; i= 2 ) { /* delete it from the bindery */ if ( gCheckMode ) printf("%s=delete\n", propName); else if ( BindCallErr(DeleteProperty(curName, curType, propName)) ) return 1; return 0; } /* not a delete, go on normally */ if ( code < 4 ) return 1; if ( ! strcmpi(sd, "static") ) dynamic = 0; else if ( ! strcmpi(sd, "dynamic") ) dynamic = 1; else return 1; if ( ! strcmpi(si, "item") ) set = 0; else if ( ! strcmpi(si, "set") ) set = 1; else return 1; /* add it to the bindery (or change it) */ if ( gCheckMode ) printf("%s=%s, %x, %s, ", propName, dynamic ? "dynamic" : "static", sec, set ? "set" : "item"); else if ( BindCallErr(CreateProperty(curName, curType, propName, (dynamic ? 1 : 0) + (set ? 2 : 0), sec)) ) return 1; /* * now get data segments and add them to that property */ /* get to point where data starts */ for ( p = line, i = 0; i < 3; i++ ) p = strchr(p+1, ','); p++; /* go though the data, writing segments */ if ( set ) { if ( insertPropSetData(curName, curType, propName, p) ) { return 1; } } else { /* item */ if ( insertPropItemData(curName, curType, propName, p) ) { return 1; } } return 0; } /* * insertObject -- reads object from input file and inserts it into bindery * returns 0 on success or eof, 1 on error */ int insertObject(char *line, char *curName, WORD *curType) { char name[49], sd[10]; /* name, static/dynamic tag */ unsigned int type; int sec; /* security */ int dynamic; /* 1 = dynamic, 0 = static */ int code; char *p; /* init */ curName[0] = '\0'; /* parse input line */ sd[0] = '\0'; code = sscanf(line, "[%48[^/]/%u, %7s %x]", name, &type, sd, &sec); /* if it's just the name/type, set our current name/type to that and return */ if ( code == 2 ) { /* make sure we've got just a group no. and ] after the / */ p = strchr(line, '/'); p++; while ( isdigit(*p) ) p++; /* skip digits */ if ( *p != ']') return 1; /* ok, save name and type and return */ strcpy(curName, name); *curType = type; if ( gCheckMode ) printf("\n[%s/%u]\n", curName, *curType); return 0; } /* check for delete function */ if ( (! strncmpi(sd, "delete", 6)) && code >= 3 ) { /* delete it from the bindery */ if ( gCheckMode ) printf("\n[%s/%u, delete]\n", name, type); else if ( BindCallErr(DeleteBinderyObject(name, type)) ) return 1; curName[0] = '\0'; /* signal for no current object */ return 0; } /* not a delete, go on normally */ if ( code < 4 ) return 1; if ( ! strcmpi(sd, "static,") ) dynamic = 0; else if ( ! strcmpi(sd, "dynamic,") ) dynamic = 1; else return 1; /* save the name and type for properties later */ strcpy(curName, name); *curType = type; /* add the object */ if ( gCheckMode ) printf("\n[%s/%u, %s, %x]\n", curName, *curType, dynamic ? "dynamic" : "static", sec); else if ( BindCallErr(CreateBinderyObject(curName, *curType, (BYTE) (dynamic ? 1 : 0), sec)) ) return 1; return 0; } /* * writebindery -- read the info out of a file and write to the bindery */ #define MAX_LINE 16536 /* maximum input line length */ int writebindery(char *filename, char *searchname, typelist *tlp) { FILE *f; char c, oldc, line[MAX_LINE+1], s[1024]; enum { read, skip } state; char curName[48]; WORD curType; int i, j; /* * first open file, if given one (else we read from stdin) */ if ( filename ) { if ( (f = fopen(filename, "r")) == NULL ) { fprintf(stderr, "bindedit: can't read from %s\n", filename); return 1; } } else { f = stdin; } /* * loop through, reading objects and inserting them into bindery */ gLineNo = 0; curName[0] = '\0'; state = read; while ( ! feof(f) ) { /* get line or error */ gLineNo++; if ( ! fgets(line, MAX_LINE, f) ) { if ( feof(f) ) return 0; fprintf(stderr, "bindedit: error reading from input\n"); return 1; } /* skip comments */ if ( line[0] == ';' ) continue; /* skip blank lines */ for ( j = 0, i = 0; i < strlen(line); i++ ) if ( ! isspace(line[i]) ) { j++; break; } if ( ! j ) continue; /* * now we change what we're looking for depending on the state */ /* skip: discard everything until we reach a new object definition */ if ( state == skip ) if ( line[0] == '[' ) state = read; else continue; line[strlen(line)-1] = '\0'; /* ditch the \n at the end */ /* read: read in objects and properties */ if ( state == read ) { if ( line[0] == '[' ) { /* object */ /* object */ if ( insertObject(line, curName, &curType) ) { fprintf(stderr, "bindedit: bad object on line %d of input\n", gLineNo); state = skip; } } else { /* property */ if ( insertProperty(line, curName, curType) ) { fprintf(stderr, "bindedit: bad property on line %d of input\n", gLineNo); state = skip; } } } } return 0; } /* * main program */ main(int argc, char *argv[]) { int writemode = -1; /* -1 = unset, 0 = read bindery, 1 = write */ typelist tl; char *filename = 0; char *searchname = "*"; /* default--search for every name */ int errflag = 0; int c, i; char *p; /* * init vars */ tl.propflags = 0x0; tl.type[0] = -1; /* * process arguments */ if ( argc < 2 || argv[1][1] == '?' ) { errflag++; writemode = 0; /* to avoid unneeded message */ } while ( (c=getopt(argc, argv, "?rcwn:t:x:")) != -1 ) switch ( c ) { case 'r' : /* read bindery */ if ( writemode != -1 ) { fprintf(stderr, "Specify one of -r, -c, -w.\n"); errflag++; } writemode = 0; break; case 'c' : /* check input file */ if ( writemode != -1 ) { fprintf(stderr, "Specify one of -r, -c, -w.\n"); errflag++; } gCheckMode = 1; writemode = 1; break; case 'w' : /* write bindery */ #ifdef WRITE_DISABLED fprintf(stderr, "bindedit: Sorry, bindery writes are disabled in this version.\n"); return 2; #else if ( writemode != -1 ) { fprintf(stderr, "Specify one of -r, -c, -w.\n"); errflag++; } gCheckMode = 0; writemode = 1; break; #endif case 'n' : /* name to search for (or wildcard) */ searchname = optarg; break; case 't' : /* list of types to search for */ p = optarg; i = 0; while ( strchr(p, ',') ) { tl.type[i++] = atoi(p); p = strchr(p, ',') + 1; } tl.type[i] = atoi(p); tl.type[i+1] = -1; break; case 'x' : /* options on what to extract */ for ( i=0; i]\n", argv[0]); return 2; } /* * run the main routine and exit with its errorcode */ if ( writemode ) return writebindery(filename, searchname, &tl); else return readbindery(filename, searchname, &tl); }