1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright (C) 2010 by the Massachusetts Institute of Technology. 4 * All rights reserved. 5 * 6 * Export of this software from the United States of America may 7 * require a specific license from the United States Government. 8 * It is the responsibility of any person or organization contemplating 9 * export to obtain such a license before exporting. 10 * 11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 12 * distribute this software and its documentation for any purpose and 13 * without fee is hereby granted, provided that the above copyright 14 * notice appear in all copies and that both that copyright notice and 15 * this permission notice appear in supporting documentation, and that 16 * the name of M.I.T. not be used in advertising or publicity pertaining 17 * to distribution of the software without specific, written prior 18 * permission. Furthermore if you modify this software you must label 19 * your software as modified software and not distribute it in such a 20 * fashion that it might be confused with the original M.I.T. software. 21 * M.I.T. makes no representations about the suitability of 22 * this software for any purpose. It is provided "as is" without express 23 * or implied warranty. 24 */ 25 /* 26 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 27 */ 28 29 #include "k5-int.h" 30 #include <kdb.h> 31 #include <ctype.h> 32 #include <pwd.h> 33 #include <syslog.h> 34 #include "server_internal.h" 35 #include <adm_proto.h> 36 37 kadm5_ret_t 38 init_pwqual(kadm5_server_handle_t handle) 39 { 40 krb5_error_code ret; 41 pwqual_handle *list; 42 const char *dict_file = NULL; 43 44 /* Register the built-in password quality modules. */ 45 ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, 46 "dict", pwqual_dict_initvt); 47 if (ret != 0) 48 return ret; 49 ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, 50 "empty", pwqual_empty_initvt); 51 if (ret != 0) 52 return ret; 53 ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, 54 "hesiod", pwqual_hesiod_initvt); 55 if (ret != 0) 56 return ret; 57 ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, 58 "princ", pwqual_princ_initvt); 59 if (ret != 0) 60 return ret; 61 62 /* Load all available password quality modules. */ 63 if (handle->params.mask & KADM5_CONFIG_DICT_FILE) 64 dict_file = handle->params.dict_file; 65 ret = k5_pwqual_load(handle->context, dict_file, &list); 66 if (ret != 0) 67 return ret; 68 69 handle->qual_handles = list; 70 return 0; 71 } 72 73 /* Check that a password meets the quality constraints given in pol. */ 74 static kadm5_ret_t 75 check_against_policy(kadm5_server_handle_t handle, const char *password, 76 kadm5_policy_ent_t pol) 77 { 78 int hasupper = 0, haslower = 0, hasdigit = 0, haspunct = 0, hasspec = 0; 79 int c, nclasses; 80 81 /* Check against the policy's minimum length. */ 82 if (strlen(password) < (size_t)pol->pw_min_length) 83 return KADM5_PASS_Q_TOOSHORT; 84 85 /* Check against the policy's minimum number of character classes. */ 86 while ((c = (unsigned char)*password++) != '\0') { 87 if (islower(c)) 88 haslower = 1; 89 else if (isupper(c)) 90 hasupper = 1; 91 else if (isdigit(c)) 92 hasdigit = 1; 93 else if (ispunct(c)) 94 haspunct = 1; 95 else 96 hasspec = 1; 97 } 98 nclasses = hasupper + haslower + hasdigit + haspunct + hasspec; 99 if (nclasses < pol->pw_min_classes) 100 return KADM5_PASS_Q_CLASS; 101 return KADM5_OK; 102 } 103 104 /* Check a password against all available password quality plugin modules 105 * and against policy. */ 106 kadm5_ret_t 107 passwd_check(kadm5_server_handle_t handle, const char *password, 108 kadm5_policy_ent_t policy, krb5_principal princ) 109 { 110 krb5_error_code ret; 111 pwqual_handle *h; 112 const char *polname = (policy == NULL) ? NULL : policy->policy; 113 114 if (policy != NULL) { 115 ret = check_against_policy(handle, password, policy); 116 if (ret != 0) 117 return ret; 118 } 119 for (h = handle->qual_handles; *h != NULL; h++) { 120 ret = k5_pwqual_check(handle->context, *h, password, polname, princ); 121 if (ret != 0) { 122 const char *e = krb5_get_error_message(handle->context, ret); 123 const char *modname = k5_pwqual_name(handle->context, *h); 124 char *princname; 125 if (krb5_unparse_name(handle->context, princ, &princname) != 0) 126 princname = NULL; 127 krb5_klog_syslog(LOG_ERR, 128 _("password quality module %s rejected password " 129 "for %s: %s"), modname, 130 princname ? princname : "(can't unparse)", e); 131 krb5_free_error_message(handle->context, e); 132 free(princname); 133 return ret; 134 } 135 } 136 return 0; 137 } 138 139 void 140 destroy_pwqual(kadm5_server_handle_t handle) 141 { 142 k5_pwqual_free_handles(handle->context, handle->qual_handles); 143 handle->qual_handles = NULL; 144 } 145 146 kadm5_ret_t 147 kadm5_get_privs(void *server_handle, long *privs) 148 { 149 CHECK_HANDLE(server_handle); 150 151 /* this is impossible to do with the current interface. For now, 152 return all privs, which will confuse some clients, but not 153 deny any access to users of "smart" clients which try to cache */ 154 155 *privs = ~0; 156 157 return KADM5_OK; 158 } 159