1 /* $NetBSD: dsaschema.c,v 1.3 2021/08/14 16:14:51 christos Exp $ */ 2 3 /* dsaschema.c */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2004-2021 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19 #include <portable.h> 20 21 #include <ac/string.h> 22 #include <ac/ctype.h> 23 #include <ac/signal.h> 24 #include <ac/errno.h> 25 #include <ac/stdlib.h> 26 #include <ac/ctype.h> 27 #include <ac/time.h> 28 #include <ac/unistd.h> 29 30 #include <stdio.h> 31 32 /* 33 * Schema reader that allows us to define DSA schema (including 34 * operational attributes and non-user object classes) 35 * 36 * A kludge, at best, and in order to avoid including slapd 37 * headers we use fprintf() rather than slapd's native logging, 38 * which may confuse users... 39 * 40 */ 41 42 #include <ldap.h> 43 #include <ldap_schema.h> 44 45 #include <slap.h> 46 #include <slap-config.h> 47 48 #define ARGS_STEP 512 49 50 static char *fp_getline(FILE *fp, int *lineno); 51 static void fp_getline_init(int *lineno); 52 static int fp_parse_line(int lineno, char *line); 53 static char *strtok_quote( char *line, char *sep ); 54 55 static char **cargv = NULL; 56 static int cargv_size = 0; 57 static int cargc = 0; 58 static char *strtok_quote_ptr; 59 60 int init_module(int argc, char *argv[]); 61 62 static int dsaschema_parse_cr(const char *fname, int lineno, char *line, char **argv) 63 { 64 struct config_args_s c = { .line = line }; 65 66 if ( parse_cr( &c, NULL ) ) { 67 Debug( LDAP_DEBUG_ANY, "dsaschema_parse_cr: " 68 "ditcontentrule definition invalid at %s:%d\n", 69 fname, lineno ); 70 return 1; 71 } 72 73 return 0; 74 } 75 76 static int dsaschema_read_config(const char *fname, int depth) 77 { 78 FILE *fp; 79 char *line, *savefname, *saveline = NULL; 80 int savelineno, lineno; 81 int rc; 82 83 if (depth == 0) { 84 cargv = ch_calloc(ARGS_STEP + 1, sizeof(*cargv)); 85 cargv_size = ARGS_STEP + 1; 86 } 87 88 fp = fopen(fname, "r"); 89 if (fp == NULL) { 90 char ebuf[128]; 91 int saved_errno = errno; 92 fprintf(stderr, "could not open config file \"%s\": %s (%d)\n", 93 fname, AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)), saved_errno); 94 return 1; 95 } 96 fp_getline_init(&lineno); 97 98 while ((line = fp_getline(fp, &lineno)) != NULL) { 99 /* skip comments and blank lines */ 100 if (line[0] == '#' || line[0] == '\0') { 101 continue; 102 } 103 104 saveline = ch_strdup(line); 105 106 if (fp_parse_line(lineno, line) != 0) { 107 rc = 1; 108 break; 109 } 110 111 if (cargc < 1) { 112 continue; 113 } 114 115 if (strcasecmp(cargv[0], "attributetype") == 0 || 116 strcasecmp(cargv[0], "attribute") == 0) { 117 if (cargc < 2) { 118 fprintf(stderr, "%s: line %d: illegal attribute type format\n", 119 fname, lineno); 120 rc = 1; 121 break; 122 } else if (*cargv[1] == '(' /*')'*/) { 123 char *p; 124 125 p = strchr(saveline, '(' /*')'*/); 126 rc = register_at(p, NULL, 0); 127 if (rc != 0) { 128 Debug( LDAP_DEBUG_ANY, "dsaschema_read_config: " 129 "attribute definition invalid at %s:%d\n", 130 fname, lineno ); 131 break; 132 } 133 } else { 134 fprintf(stderr, "%s: line %d: old attribute type format not supported\n", 135 fname, lineno); 136 } 137 } else if (strcasecmp(cargv[0], "ditcontentrule") == 0) { 138 char *p; 139 p = strchr(saveline, '(' /*')'*/); 140 rc = dsaschema_parse_cr(fname, lineno, p, cargv); 141 if (rc != 0) 142 break; 143 } else if (strcasecmp(cargv[0], "objectclass") == 0) { 144 if (cargc < 2) { 145 fprintf(stderr, "%s: line %d: illegal objectclass format\n", 146 fname, lineno); 147 rc = 1; 148 break; 149 } else if (*cargv[1] == '(' /*')'*/) { 150 char *p; 151 152 p = strchr(saveline, '(' /*')'*/); 153 rc = register_oc(p, NULL, 0); 154 if (rc != 0) { 155 Debug( LDAP_DEBUG_ANY, "dsaschema_read_config: " 156 "objectclass definition invalid at %s:%d\n", 157 fname, lineno ); 158 break; 159 } 160 } else { 161 fprintf(stderr, "%s: line %d: object class format not supported\n", 162 fname, lineno); 163 } 164 } else if (strcasecmp(cargv[0], "include") == 0) { 165 if (cargc < 2) { 166 fprintf(stderr, "%s: line %d: missing file name in \"include <filename>\" line", 167 fname, lineno); 168 rc = 1; 169 break; 170 } 171 savelineno = lineno; 172 savefname = ch_strdup(cargv[1]); 173 174 rc = dsaschema_read_config(savefname, depth + 1); 175 ch_free(savefname); 176 lineno = savelineno - 1; 177 if (rc != 0) { 178 break; 179 } 180 } else { 181 fprintf(stderr, "%s: line %d: unknown directive \"%s\" (ignored)\n", 182 fname, lineno, cargv[0]); 183 } 184 185 ch_free(saveline); 186 saveline = NULL; 187 } 188 189 fclose(fp); 190 191 if (depth == 0) 192 ch_free(cargv); 193 194 if (saveline != NULL) 195 ch_free(saveline); 196 197 return rc; 198 } 199 200 int init_module(int argc, char *argv[]) 201 { 202 int i; 203 int rc; 204 205 for (i = 0; i < argc; i++) { 206 rc = dsaschema_read_config(argv[i], 0); 207 if (rc != 0) { 208 break; 209 } 210 } 211 212 return rc; 213 } 214 215 216 static int 217 fp_parse_line( 218 int lineno, 219 char *line 220 ) 221 { 222 char * token; 223 224 cargc = 0; 225 token = strtok_quote( line, " \t" ); 226 227 if ( strtok_quote_ptr ) { 228 *strtok_quote_ptr = ' '; 229 } 230 231 if ( strtok_quote_ptr ) { 232 *strtok_quote_ptr = '\0'; 233 } 234 235 for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) { 236 if ( cargc == cargv_size - 1 ) { 237 char **tmp; 238 tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) * 239 sizeof(*cargv) ); 240 cargv = tmp; 241 cargv_size += ARGS_STEP; 242 } 243 cargv[cargc++] = token; 244 } 245 cargv[cargc] = NULL; 246 return 0; 247 } 248 249 static char * 250 strtok_quote( char *line, char *sep ) 251 { 252 int inquote; 253 char *tmp; 254 static char *next; 255 256 strtok_quote_ptr = NULL; 257 if ( line != NULL ) { 258 next = line; 259 } 260 while ( *next && strchr( sep, *next ) ) { 261 next++; 262 } 263 264 if ( *next == '\0' ) { 265 next = NULL; 266 return( NULL ); 267 } 268 tmp = next; 269 270 for ( inquote = 0; *next; ) { 271 switch ( *next ) { 272 case '"': 273 if ( inquote ) { 274 inquote = 0; 275 } else { 276 inquote = 1; 277 } 278 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 ); 279 break; 280 281 case '\\': 282 if ( next[1] ) 283 AC_MEMCPY( next, 284 next + 1, strlen( next + 1 ) + 1 ); 285 next++; /* dont parse the escaped character */ 286 break; 287 288 default: 289 if ( ! inquote ) { 290 if ( strchr( sep, *next ) != NULL ) { 291 strtok_quote_ptr = next; 292 *next++ = '\0'; 293 return( tmp ); 294 } 295 } 296 next++; 297 break; 298 } 299 } 300 301 return( tmp ); 302 } 303 304 static char buf[BUFSIZ]; 305 static char *line; 306 static size_t lmax, lcur; 307 308 #define CATLINE( buf ) \ 309 do { \ 310 size_t len = strlen( buf ); \ 311 while ( lcur + len + 1 > lmax ) { \ 312 lmax += BUFSIZ; \ 313 line = (char *) ch_realloc( line, lmax ); \ 314 } \ 315 strcpy( line + lcur, buf ); \ 316 lcur += len; \ 317 } while( 0 ) 318 319 static char * 320 fp_getline( FILE *fp, int *lineno ) 321 { 322 char *p; 323 324 lcur = 0; 325 CATLINE( buf ); 326 (*lineno)++; 327 328 /* hack attack - keeps us from having to keep a stack of bufs... */ 329 if ( strncasecmp( line, "include", 7 ) == 0 ) { 330 buf[0] = '\0'; 331 return( line ); 332 } 333 334 while ( fgets( buf, sizeof(buf), fp ) != NULL ) { 335 /* trim off \r\n or \n */ 336 if ( (p = strchr( buf, '\n' )) != NULL ) { 337 if( p > buf && p[-1] == '\r' ) --p; 338 *p = '\0'; 339 } 340 341 /* trim off trailing \ and append the next line */ 342 if ( line[ 0 ] != '\0' 343 && (p = line + strlen( line ) - 1)[ 0 ] == '\\' 344 && p[ -1 ] != '\\' ) { 345 p[ 0 ] = '\0'; 346 lcur--; 347 348 } else { 349 if ( ! isspace( (unsigned char) buf[0] ) ) { 350 return( line ); 351 } 352 353 /* change leading whitespace to a space */ 354 buf[0] = ' '; 355 } 356 357 CATLINE( buf ); 358 (*lineno)++; 359 } 360 buf[0] = '\0'; 361 362 return( line[0] ? line : NULL ); 363 } 364 365 static void 366 fp_getline_init( int *lineno ) 367 { 368 *lineno = -1; 369 buf[0] = '\0'; 370 } 371 372