xref: /freebsd/crypto/krb5/src/lib/kadm5/srv/svr_iters.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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  */
glob_to_regexp(char * glob,char * realm,char ** regexp)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 
get_either_iter(struct iter_data * data,char * name)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 
get_pols_iter(void * data,osa_policy_ent_t entry)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 
get_princs_iter(void * data,krb5_principal princ)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 
kadm5_get_either(int princ,void * server_handle,char * exp,char *** princs,int * count)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                               &regexp)) != 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 
kadm5_get_principals(void * server_handle,char * exp,char *** princs,int * count)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 
kadm5_get_policies(void * server_handle,char * exp,char *** pols,int * count)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