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 <sys/types.h>
9 #include <kadm5/admin.h>
10 #include "server_internal.h"
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14
15 #define MIN_PW_HISTORY 1
16 #define MIN_PW_CLASSES 1
17 #define MAX_PW_CLASSES 5
18 #define MIN_PW_LENGTH 1
19
20 /* Validate allowed_keysalts. */
21 static kadm5_ret_t
validate_allowed_keysalts(const char * allowed_keysalts)22 validate_allowed_keysalts(const char *allowed_keysalts)
23 {
24 kadm5_ret_t ret;
25 krb5_key_salt_tuple *ks_tuple = NULL;
26 krb5_int32 n_ks_tuple = 0;
27
28 if (strchr(allowed_keysalts, '\t') != NULL)
29 return KADM5_BAD_KEYSALTS;
30 ret = krb5_string_to_keysalts(allowed_keysalts, ",", NULL, 0,
31 &ks_tuple, &n_ks_tuple);
32 free(ks_tuple);
33 if (ret == EINVAL)
34 return KADM5_BAD_KEYSALTS;
35 return ret;
36 }
37
38 /*
39 * Function: kadm5_create_policy
40 *
41 * Purpose: Create Policies in the policy DB.
42 *
43 * Arguments:
44 * entry (input) The policy entry to be written out to the DB.
45 * mask (input) Specifies which fields in entry are to ge written out
46 * and which get default values.
47 * <return value> 0 if successful otherwise an error code is returned.
48 *
49 * Requires:
50 * Entry must be a valid principal entry, and mask have a valid value.
51 *
52 * Effects:
53 * Writes the data to the database, and does a database sync if
54 * successful.
55 *
56 */
57
58 kadm5_ret_t
kadm5_create_policy(void * server_handle,kadm5_policy_ent_t entry,long mask)59 kadm5_create_policy(void *server_handle, kadm5_policy_ent_t entry, long mask)
60 {
61 kadm5_server_handle_t handle = server_handle;
62 osa_policy_ent_rec pent, *check_pol;
63 int ret;
64 char *p;
65
66 CHECK_HANDLE(server_handle);
67
68 krb5_clear_error_message(handle->context);
69
70 if ((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL))
71 return EINVAL;
72 if(strlen(entry->policy) == 0)
73 return KADM5_BAD_POLICY;
74 if (!(mask & KADM5_POLICY) || (mask & ~ALL_POLICY_MASK))
75 return KADM5_BAD_MASK;
76 if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS) &&
77 entry->allowed_keysalts != NULL) {
78 ret = validate_allowed_keysalts(entry->allowed_keysalts);
79 if (ret)
80 return ret;
81 }
82
83 ret = krb5_db_get_policy(handle->context, entry->policy, &check_pol);
84 if (!ret) {
85 krb5_db_free_policy(handle->context, check_pol);
86 return KADM5_DUP;
87 } else if (ret != KRB5_KDB_NOENTRY) {
88 return ret;
89 }
90
91 memset(&pent, 0, sizeof(pent));
92 pent.name = entry->policy;
93 p = entry->policy;
94 while(*p != '\0') {
95 if(*p < ' ' || *p > '~')
96 return KADM5_BAD_POLICY;
97 else
98 p++;
99 }
100 if (!(mask & KADM5_PW_MAX_LIFE))
101 pent.pw_max_life = 0;
102 else
103 pent.pw_max_life = entry->pw_max_life;
104 if (!(mask & KADM5_PW_MIN_LIFE))
105 pent.pw_min_life = 0;
106 else {
107 if((mask & KADM5_PW_MAX_LIFE)) {
108 if(entry->pw_min_life > entry->pw_max_life && entry->pw_max_life != 0)
109 return KADM5_BAD_MIN_PASS_LIFE;
110 }
111 pent.pw_min_life = entry->pw_min_life;
112 }
113 if (!(mask & KADM5_PW_MIN_LENGTH))
114 pent.pw_min_length = MIN_PW_LENGTH;
115 else {
116 if(entry->pw_min_length < MIN_PW_LENGTH)
117 return KADM5_BAD_LENGTH;
118 pent.pw_min_length = entry->pw_min_length;
119 }
120 if (!(mask & KADM5_PW_MIN_CLASSES))
121 pent.pw_min_classes = MIN_PW_CLASSES;
122 else {
123 if(entry->pw_min_classes > MAX_PW_CLASSES || entry->pw_min_classes < MIN_PW_CLASSES)
124 return KADM5_BAD_CLASS;
125 pent.pw_min_classes = entry->pw_min_classes;
126 }
127 if (!(mask & KADM5_PW_HISTORY_NUM))
128 pent.pw_history_num = MIN_PW_HISTORY;
129 else {
130 if(entry->pw_history_num < MIN_PW_HISTORY)
131 return KADM5_BAD_HISTORY;
132 else
133 pent.pw_history_num = entry->pw_history_num;
134 }
135
136 if (handle->api_version >= KADM5_API_VERSION_4) {
137 if (!(mask & KADM5_POLICY_ATTRIBUTES))
138 pent.attributes = 0;
139 else
140 pent.attributes = entry->attributes;
141 if (!(mask & KADM5_POLICY_MAX_LIFE))
142 pent.max_life = 0;
143 else
144 pent.max_life = entry->max_life;
145 if (!(mask & KADM5_POLICY_MAX_RLIFE))
146 pent.max_renewable_life = 0;
147 else
148 pent.max_renewable_life = entry->max_renewable_life;
149 if (!(mask & KADM5_POLICY_ALLOWED_KEYSALTS))
150 pent.allowed_keysalts = 0;
151 else
152 pent.allowed_keysalts = entry->allowed_keysalts;
153 if (!(mask & KADM5_POLICY_TL_DATA)) {
154 pent.n_tl_data = 0;
155 pent.tl_data = NULL;
156 } else {
157 pent.n_tl_data = entry->n_tl_data;
158 pent.tl_data = entry->tl_data;
159 }
160 }
161 if (handle->api_version >= KADM5_API_VERSION_3) {
162 if (!(mask & KADM5_PW_MAX_FAILURE))
163 pent.pw_max_fail = 0;
164 else
165 pent.pw_max_fail = entry->pw_max_fail;
166 if (!(mask & KADM5_PW_FAILURE_COUNT_INTERVAL))
167 pent.pw_failcnt_interval = 0;
168 else
169 pent.pw_failcnt_interval = entry->pw_failcnt_interval;
170 if (!(mask & KADM5_PW_LOCKOUT_DURATION))
171 pent.pw_lockout_duration = 0;
172 else
173 pent.pw_lockout_duration = entry->pw_lockout_duration;
174 }
175
176 if ((ret = krb5_db_create_policy(handle->context, &pent)))
177 return ret;
178 else
179 return KADM5_OK;
180 }
181
182 kadm5_ret_t
kadm5_delete_policy(void * server_handle,kadm5_policy_t name)183 kadm5_delete_policy(void *server_handle, kadm5_policy_t name)
184 {
185 kadm5_server_handle_t handle = server_handle;
186 osa_policy_ent_t entry;
187 int ret;
188
189 CHECK_HANDLE(server_handle);
190
191 krb5_clear_error_message(handle->context);
192
193 if(name == (kadm5_policy_t) NULL)
194 return EINVAL;
195 if(strlen(name) == 0)
196 return KADM5_BAD_POLICY;
197 ret = krb5_db_get_policy(handle->context, name, &entry);
198 if (ret == KRB5_KDB_NOENTRY)
199 return KADM5_UNK_POLICY;
200 else if (ret)
201 return ret;
202
203 krb5_db_free_policy(handle->context, entry);
204 ret = krb5_db_delete_policy(handle->context, name);
205 if (ret == KRB5_KDB_POLICY_REF)
206 ret = KADM5_POLICY_REF;
207 return (ret == 0) ? KADM5_OK : ret;
208 }
209
210 /* Allocate and form a TL data list of a desired size. */
211 static int
alloc_tl_data(krb5_int16 n_tl_data,krb5_tl_data ** tldp)212 alloc_tl_data(krb5_int16 n_tl_data, krb5_tl_data **tldp)
213 {
214 krb5_tl_data **tlp = tldp;
215 int i;
216
217 for (i = 0; i < n_tl_data; i++) {
218 *tlp = calloc(1, sizeof(krb5_tl_data));
219 if (*tlp == NULL)
220 return ENOMEM; /* caller cleans up */
221 memset(*tlp, 0, sizeof(krb5_tl_data));
222 tlp = &((*tlp)->tl_data_next);
223 }
224
225 return 0;
226 }
227
228 static kadm5_ret_t
copy_tl_data(krb5_int16 n_tl_data,krb5_tl_data * tl_data,krb5_tl_data ** out)229 copy_tl_data(krb5_int16 n_tl_data, krb5_tl_data *tl_data,
230 krb5_tl_data **out)
231 {
232 kadm5_ret_t ret;
233 krb5_tl_data *tl, *tl_new;
234
235 if ((ret = alloc_tl_data(n_tl_data, out)))
236 return ret; /* caller cleans up */
237
238 tl = tl_data;
239 tl_new = *out;
240 for (; tl; tl = tl->tl_data_next, tl_new = tl_new->tl_data_next) {
241 tl_new->tl_data_contents = malloc(tl->tl_data_length);
242 if (tl_new->tl_data_contents == NULL)
243 return ENOMEM;
244 memcpy(tl_new->tl_data_contents, tl->tl_data_contents,
245 tl->tl_data_length);
246 tl_new->tl_data_type = tl->tl_data_type;
247 tl_new->tl_data_length = tl->tl_data_length;
248 }
249
250 return 0;
251 }
252
253 kadm5_ret_t
kadm5_modify_policy(void * server_handle,kadm5_policy_ent_t entry,long mask)254 kadm5_modify_policy(void *server_handle, kadm5_policy_ent_t entry, long mask)
255 {
256 kadm5_server_handle_t handle = server_handle;
257 krb5_tl_data *tl;
258 osa_policy_ent_t p;
259 int ret;
260
261 CHECK_HANDLE(server_handle);
262
263 krb5_clear_error_message(handle->context);
264
265 if((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL))
266 return EINVAL;
267 if(strlen(entry->policy) == 0)
268 return KADM5_BAD_POLICY;
269 if ((mask & KADM5_POLICY) || (mask & ~ALL_POLICY_MASK))
270 return KADM5_BAD_MASK;
271 if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS) &&
272 entry->allowed_keysalts != NULL) {
273 ret = validate_allowed_keysalts(entry->allowed_keysalts);
274 if (ret)
275 return ret;
276 }
277 if ((mask & KADM5_POLICY_TL_DATA)) {
278 tl = entry->tl_data;
279 while (tl != NULL) {
280 if (tl->tl_data_type < 256)
281 return KADM5_BAD_TL_TYPE;
282 tl = tl->tl_data_next;
283 }
284 }
285
286 ret = krb5_db_get_policy(handle->context, entry->policy, &p);
287 if (ret == KRB5_KDB_NOENTRY)
288 return KADM5_UNK_POLICY;
289 else if (ret)
290 return ret;
291
292 if ((mask & KADM5_PW_MAX_LIFE))
293 p->pw_max_life = entry->pw_max_life;
294 if ((mask & KADM5_PW_MIN_LIFE)) {
295 if(entry->pw_min_life > p->pw_max_life && p->pw_max_life != 0) {
296 krb5_db_free_policy(handle->context, p);
297 return KADM5_BAD_MIN_PASS_LIFE;
298 }
299 p->pw_min_life = entry->pw_min_life;
300 }
301 if ((mask & KADM5_PW_MIN_LENGTH)) {
302 if(entry->pw_min_length < MIN_PW_LENGTH) {
303 krb5_db_free_policy(handle->context, p);
304 return KADM5_BAD_LENGTH;
305 }
306 p->pw_min_length = entry->pw_min_length;
307 }
308 if ((mask & KADM5_PW_MIN_CLASSES)) {
309 if(entry->pw_min_classes > MAX_PW_CLASSES ||
310 entry->pw_min_classes < MIN_PW_CLASSES) {
311 krb5_db_free_policy(handle->context, p);
312 return KADM5_BAD_CLASS;
313 }
314 p->pw_min_classes = entry->pw_min_classes;
315 }
316 if ((mask & KADM5_PW_HISTORY_NUM)) {
317 if(entry->pw_history_num < MIN_PW_HISTORY) {
318 krb5_db_free_policy(handle->context, p);
319 return KADM5_BAD_HISTORY;
320 }
321 p->pw_history_num = entry->pw_history_num;
322 }
323 if (handle->api_version >= KADM5_API_VERSION_3) {
324 if ((mask & KADM5_PW_MAX_FAILURE))
325 p->pw_max_fail = entry->pw_max_fail;
326 if ((mask & KADM5_PW_FAILURE_COUNT_INTERVAL))
327 p->pw_failcnt_interval = entry->pw_failcnt_interval;
328 if ((mask & KADM5_PW_LOCKOUT_DURATION))
329 p->pw_lockout_duration = entry->pw_lockout_duration;
330 }
331 if (handle->api_version >= KADM5_API_VERSION_4) {
332 if ((mask & KADM5_POLICY_ATTRIBUTES))
333 p->attributes = entry->attributes;
334 if ((mask & KADM5_POLICY_MAX_LIFE))
335 p->max_life = entry->max_life;
336 if ((mask & KADM5_POLICY_MAX_RLIFE))
337 p->max_renewable_life = entry->max_renewable_life;
338 if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS)) {
339 free(p->allowed_keysalts);
340 p->allowed_keysalts = NULL;
341 if (entry->allowed_keysalts != NULL) {
342 p->allowed_keysalts = strdup(entry->allowed_keysalts);
343 if (p->allowed_keysalts == NULL) {
344 ret = ENOMEM;
345 goto cleanup;
346 }
347 }
348 }
349 if ((mask & KADM5_POLICY_TL_DATA)) {
350 for (tl = entry->tl_data; tl != NULL; tl = tl->tl_data_next) {
351 ret = krb5_db_update_tl_data(handle->context, &p->n_tl_data,
352 &p->tl_data, tl);
353 if (ret)
354 goto cleanup;
355 }
356 }
357 }
358 ret = krb5_db_put_policy(handle->context, p);
359
360 cleanup:
361 krb5_db_free_policy(handle->context, p);
362 return ret;
363 }
364
365 kadm5_ret_t
kadm5_get_policy(void * server_handle,kadm5_policy_t name,kadm5_policy_ent_t entry)366 kadm5_get_policy(void *server_handle, kadm5_policy_t name,
367 kadm5_policy_ent_t entry)
368 {
369 osa_policy_ent_t t;
370 kadm5_ret_t ret;
371 kadm5_server_handle_t handle = server_handle;
372
373 memset(entry, 0, sizeof(*entry));
374
375 CHECK_HANDLE(server_handle);
376
377 krb5_clear_error_message(handle->context);
378
379 if (name == (kadm5_policy_t) NULL)
380 return EINVAL;
381 if(strlen(name) == 0)
382 return KADM5_BAD_POLICY;
383 ret = krb5_db_get_policy(handle->context, name, &t);
384 if (ret == KRB5_KDB_NOENTRY)
385 return KADM5_UNK_POLICY;
386 else if (ret)
387 return ret;
388
389 if ((entry->policy = strdup(t->name)) == NULL) {
390 ret = ENOMEM;
391 goto cleanup;
392 }
393 entry->pw_min_life = t->pw_min_life;
394 entry->pw_max_life = t->pw_max_life;
395 entry->pw_min_length = t->pw_min_length;
396 entry->pw_min_classes = t->pw_min_classes;
397 entry->pw_history_num = t->pw_history_num;
398 if (handle->api_version >= KADM5_API_VERSION_3) {
399 entry->pw_max_fail = t->pw_max_fail;
400 entry->pw_failcnt_interval = t->pw_failcnt_interval;
401 entry->pw_lockout_duration = t->pw_lockout_duration;
402 }
403 if (handle->api_version >= KADM5_API_VERSION_4) {
404 entry->attributes = t->attributes;
405 entry->max_life = t->max_life;
406 entry->max_renewable_life = t->max_renewable_life;
407 if (t->allowed_keysalts) {
408 entry->allowed_keysalts = strdup(t->allowed_keysalts);
409 if (!entry->allowed_keysalts) {
410 ret = ENOMEM;
411 goto cleanup;
412 }
413 }
414 ret = copy_tl_data(t->n_tl_data, t->tl_data, &entry->tl_data);
415 if (ret)
416 goto cleanup;
417 entry->n_tl_data = t->n_tl_data;
418 }
419
420 ret = 0;
421
422 cleanup:
423 if (ret)
424 kadm5_free_policy_ent(handle, entry);
425 krb5_db_free_policy(handle->context, t);
426 return ret;
427 }
428