1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 4 * 5 * $Header$ 6 */ 7 8 #include "autoconf.h" 9 #if defined(HAVE_COMPILE) && defined(HAVE_STEP) 10 #define SOLARIS_REGEXPS 11 #elif defined(HAVE_REGCOMP) && defined(HAVE_REGEXEC) 12 #define POSIX_REGEXPS 13 #elif defined(HAVE_RE_COMP) && defined(HAVE_RE_EXEC) 14 #define BSD_REGEXPS 15 #else 16 #error I cannot find any regexp functions 17 #endif 18 19 #include <sys/types.h> 20 #include <string.h> 21 #include <kadm5/admin.h> 22 #ifdef SOLARIS_REGEXPS 23 #include <regexpr.h> 24 #endif 25 #ifdef POSIX_REGEXPS 26 #include <regex.h> 27 #endif 28 #include <stdlib.h> 29 30 #include "server_internal.h" 31 32 struct iter_data { 33 krb5_context context; 34 char **names; 35 int n_names, sz_names; 36 unsigned int malloc_failed; 37 char *exp; 38 #ifdef SOLARIS_REGEXPS 39 char *expbuf; 40 #endif 41 #ifdef POSIX_REGEXPS 42 regex_t preg; 43 #endif 44 }; 45 46 /* XXX Duplicated in kdb5_util! */ 47 /* 48 * Function: glob_to_regexp 49 * 50 * Arguments: 51 * 52 * glob (r) the shell-style glob (?*[]) to convert 53 * realm (r) the default realm to append, or NULL 54 * regexp (w) the ed-style regexp created from glob 55 * 56 * Effects: 57 * 58 * regexp is filled in with allocated memory contained a regular 59 * expression to be used with re_comp/compile that matches what the 60 * shell-style glob would match. If glob does not contain an "@" 61 * character and realm is not NULL, "@*" is appended to the regexp. 62 * 63 * Conversion algorithm: 64 * 65 * quoted characters are copied quoted 66 * ? is converted to . 67 * * is converted to .* 68 * active characters are quoted: ^, $, . 69 * [ and ] are active but supported and have the same meaning, so 70 * they are copied 71 * other characters are copied 72 * regexp is anchored with ^ and $ 73 */ 74 static kadm5_ret_t glob_to_regexp(char *glob, char *realm, char **regexp) 75 { 76 int append_realm; 77 char *p; 78 79 /* validate the glob */ 80 if (glob[strlen(glob)-1] == '\\') 81 return EINVAL; 82 83 /* A character of glob can turn into two in regexp, plus ^ and $ */ 84 /* and trailing null. If glob has no @, also allocate space for */ 85 /* the realm. */ 86 append_realm = (realm != NULL) && (strchr(glob, '@') == NULL); 87 p = (char *) malloc(strlen(glob)*2+ 3 + (append_realm ? 3 : 0)); 88 if (p == NULL) 89 return ENOMEM; 90 *regexp = p; 91 92 *p++ = '^'; 93 while (*glob) { 94 switch (*glob) { 95 case '?': 96 *p++ = '.'; 97 break; 98 case '*': 99 *p++ = '.'; 100 *p++ = '*'; 101 break; 102 case '.': 103 case '^': 104 case '$': 105 *p++ = '\\'; 106 *p++ = *glob; 107 break; 108 case '\\': 109 *p++ = '\\'; 110 *p++ = *++glob; 111 break; 112 default: 113 *p++ = *glob; 114 break; 115 } 116 glob++; 117 } 118 119 if (append_realm) { 120 *p++ = '@'; 121 *p++ = '.'; 122 *p++ = '*'; 123 } 124 125 *p++ = '$'; 126 *p++ = '\0'; 127 return KADM5_OK; 128 } 129 130 static void get_either_iter(struct iter_data *data, char *name) 131 { 132 int match; 133 #ifdef SOLARIS_REGEXPS 134 match = (step(name, data->expbuf) != 0); 135 #endif 136 #ifdef POSIX_REGEXPS 137 match = (regexec(&data->preg, name, 0, NULL, 0) == 0); 138 #endif 139 #ifdef BSD_REGEXPS 140 match = (re_exec(name) != 0); 141 #endif 142 if (match) { 143 if (data->n_names == data->sz_names) { 144 int new_sz = data->sz_names * 2; 145 char **new_names = realloc(data->names, 146 new_sz * sizeof(char *)); 147 if (new_names) { 148 data->names = new_names; 149 data->sz_names = new_sz; 150 } else { 151 data->malloc_failed = 1; 152 free(name); 153 return; 154 } 155 } 156 data->names[data->n_names++] = name; 157 } else 158 free(name); 159 } 160 161 static void get_pols_iter(void *data, osa_policy_ent_t entry) 162 { 163 char *name; 164 165 if ((name = strdup(entry->name)) == NULL) 166 return; 167 get_either_iter(data, name); 168 } 169 170 static void get_princs_iter(void *data, krb5_principal princ) 171 { 172 struct iter_data *id = (struct iter_data *) data; 173 char *name; 174 175 if (krb5_unparse_name(id->context, princ, &name) != 0) 176 return; 177 get_either_iter(data, name); 178 } 179 180 static kadm5_ret_t kadm5_get_either(int princ, 181 void *server_handle, 182 char *exp, 183 char ***princs, 184 int *count) 185 { 186 struct iter_data data; 187 #ifdef BSD_REGEXPS 188 char *msg; 189 #endif 190 char *regexp = NULL; 191 int i, ret; 192 kadm5_server_handle_t handle = server_handle; 193 194 *princs = NULL; 195 *count = 0; 196 if (exp == NULL) 197 exp = "*"; 198 199 CHECK_HANDLE(server_handle); 200 201 if ((ret = glob_to_regexp(exp, princ ? handle->params.realm : NULL, 202 ®exp)) != KADM5_OK) 203 return ret; 204 205 if ( 206 #ifdef SOLARIS_REGEXPS 207 ((data.expbuf = compile(regexp, NULL, NULL)) == NULL) 208 #endif 209 #ifdef POSIX_REGEXPS 210 ((regcomp(&data.preg, regexp, REG_NOSUB)) != 0) 211 #endif 212 #ifdef BSD_REGEXPS 213 ((msg = (char *) re_comp(regexp)) != NULL) 214 #endif 215 ) 216 { 217 /* XXX syslog msg or regerr(regerrno) */ 218 free(regexp); 219 return EINVAL; 220 } 221 222 data.n_names = 0; 223 data.sz_names = 10; 224 data.malloc_failed = 0; 225 data.names = malloc(sizeof(char *) * data.sz_names); 226 if (data.names == NULL) { 227 free(regexp); 228 return ENOMEM; 229 } 230 231 if (princ) { 232 data.context = handle->context; 233 ret = kdb_iter_entry(handle, exp, get_princs_iter, (void *) &data); 234 } else { 235 ret = krb5_db_iter_policy(handle->context, exp, get_pols_iter, (void *)&data); 236 } 237 238 free(regexp); 239 #ifdef POSIX_REGEXPS 240 regfree(&data.preg); 241 #endif 242 if ( !ret && data.malloc_failed) 243 ret = ENOMEM; 244 if ( ret ) { 245 for (i = 0; i < data.n_names; i++) 246 free(data.names[i]); 247 free(data.names); 248 return ret; 249 } 250 251 *princs = data.names; 252 *count = data.n_names; 253 return KADM5_OK; 254 } 255 256 kadm5_ret_t kadm5_get_principals(void *server_handle, 257 char *exp, 258 char ***princs, 259 int *count) 260 { 261 return kadm5_get_either(1, server_handle, exp, princs, count); 262 } 263 264 kadm5_ret_t kadm5_get_policies(void *server_handle, 265 char *exp, 266 char ***pols, 267 int *count) 268 { 269 return kadm5_get_either(0, server_handle, exp, pols, count); 270 } 271