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 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 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 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 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 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 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 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