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