1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * lib/kdb/kdb_ldap/ldap_service_stash.c 8 * 9 * Copyright (c) 2004-2005, Novell, Inc. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions are met: 14 * 15 * * Redistributions of source code must retain the above copyright notice, 16 * this list of conditions and the following disclaimer. 17 * * Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * * The copyright holder's name is not used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include <ctype.h> 37 #include "ldap_main.h" 38 #include "kdb_ldap.h" 39 #include "ldap_service_stash.h" 40 #include <libintl.h> 41 42 krb5_error_code 43 krb5_ldap_readpassword(context, ldap_context, password) 44 krb5_context context; 45 krb5_ldap_context *ldap_context; 46 unsigned char **password; 47 { 48 int entryfound=0; 49 krb5_error_code st=0; 50 char line[RECORDLEN]="0", *start=NULL, *file=NULL; 51 char errbuf[1024]; 52 FILE *fptr=NULL; 53 54 *password = NULL; 55 56 if (ldap_context->service_password_file) 57 file = ldap_context->service_password_file; 58 59 #ifndef HAVE_STRERROR_R 60 # undef strerror_r 61 /* Solaris Kerberos: safer macro, added more (), use strlcpy() */ 62 # define strerror_r(ERRNUM, BUF, SIZE) (strlcpy((BUF), strerror(ERRNUM), (SIZE)), (BUF)[(SIZE)-1] = 0) 63 #endif 64 65 /* Solaris Kerberos: access()'s are unsafe and useless */ 66 #if 0 /************** Begin IFDEF'ed OUT *******************************/ 67 /* check whether file exists */ 68 if (access(file, F_OK) < 0) { 69 st = errno; 70 strerror_r(errno, errbuf, sizeof(errbuf)); 71 krb5_set_error_message (context, st, "%s", errbuf); 72 goto rp_exit; 73 } 74 75 /* check read access */ 76 if (access(file, R_OK) < 0) { 77 st = errno; 78 strerror_r(errno, errbuf, sizeof(errbuf)); 79 krb5_set_error_message (context, st, "%s", errbuf); 80 goto rp_exit; 81 } 82 #endif /**************** END IFDEF'ed OUT *******************************/ 83 84 /* Solaris Kerberos: using F to deal with 256 open file limit */ 85 if ((fptr = fopen(file, "rF")) == NULL) { 86 st = errno; 87 strerror_r(errno, errbuf, sizeof(errbuf)); 88 krb5_set_error_message (context, st, "%s", errbuf); 89 goto rp_exit; 90 } 91 92 /* get the record from the file */ 93 while (fgets(line, RECORDLEN, fptr) != NULL) { 94 char tmp[RECORDLEN]; 95 96 tmp[0] = '\0'; 97 /* Handle leading white-spaces */ 98 for (start = line; isspace(*start); ++start); 99 100 /* Handle comment lines */ 101 if (*start == '!' || *start == '#') 102 continue; 103 sscanf(line, "%*[ \t]%[^#]", tmp); 104 if (tmp[0] == '\0') 105 sscanf(line, "%[^#]", tmp); 106 if (strcasecmp(tmp, ldap_context->bind_dn) == 0) { 107 entryfound = 1; /* service_dn record found !!! */ 108 break; 109 } 110 } 111 (void) fclose (fptr); 112 113 if (entryfound == 0) { 114 st = KRB5_KDB_SERVER_INTERNAL_ERR; 115 krb5_set_error_message (context, st, gettext("Bind DN entry missing in stash file")); 116 goto rp_exit; 117 } 118 /* replace the \n with \0 */ 119 start = strchr(line, '\n'); 120 if (start) 121 *start = '\0'; 122 123 start = strchr(line, '#'); 124 if (start == NULL) { 125 /* password field missing */ 126 st = KRB5_KDB_SERVER_INTERNAL_ERR; 127 krb5_set_error_message (context, st, gettext("Stash file entry corrupt")); 128 goto rp_exit; 129 } 130 ++ start; 131 /* Extract the plain password / certificate file information */ 132 { 133 struct data PT, CT; 134 135 /* Check if the entry has the path of a certificate */ 136 if (!strncmp(start, "{FILE}", strlen("{FILE}"))) { 137 /* Set *password = {FILE}<path to cert>\0<cert password> */ 138 /*ptr = strchr(start, ':'); 139 if (ptr == NULL) { */ 140 *password = (unsigned char *)malloc(strlen(start) + 2); 141 if (*password == NULL) { 142 st = ENOMEM; 143 goto rp_exit; 144 } 145 (*password)[strlen(start) + 1] = '\0'; 146 (*password)[strlen(start)] = '\0'; 147 /*LINTED*/ 148 strcpy((char *)(*password), start); 149 goto got_password; 150 } else { 151 CT.value = (unsigned char *)start; 152 CT.len = strlen((char *)CT.value); 153 st = dec_password(CT, &PT); 154 if (st != 0) { 155 switch (st) { 156 case ERR_NO_MEM: 157 st = ENOMEM; 158 break; 159 case ERR_PWD_ZERO: 160 st = EINVAL; 161 krb5_set_error_message(context, st, gettext("Password has zero length")); 162 break; 163 case ERR_PWD_BAD: 164 st = EINVAL; 165 krb5_set_error_message(context, st, gettext("Password corrupted")); 166 break; 167 case ERR_PWD_NOT_HEX: 168 st = EINVAL; 169 krb5_set_error_message(context, st, gettext("Not a hexadecimal password")); 170 break; 171 default: 172 st = KRB5_KDB_SERVER_INTERNAL_ERR; 173 break; 174 } 175 goto rp_exit; 176 } 177 *password = PT.value; 178 } 179 } 180 got_password: 181 182 rp_exit: 183 if (st) { 184 if (*password) 185 free (*password); 186 *password = NULL; 187 } 188 return st; 189 } 190 191 /* Encodes a sequence of bytes in hexadecimal */ 192 193 int 194 tohex(in, ret) 195 krb5_data in; 196 krb5_data *ret; 197 { 198 int i=0, err = 0; 199 200 ret->length = 0; 201 ret->data = NULL; 202 203 ret->data = malloc((unsigned int)in.length * 2 + 1 /*Null termination */); 204 if (ret->data == NULL) { 205 err = ENOMEM; 206 goto cleanup; 207 } 208 ret->length = in.length * 2; 209 ret->data[ret->length] = 0; 210 211 for (i = 0; i < in.length; i++) 212 sprintf(ret->data + (2 * i), "%02x", in.data[i] & 0xff); 213 214 cleanup: 215 216 if (ret->length == 0) { 217 free(ret->data); 218 ret->data = NULL; 219 } 220 221 return err; 222 } 223 224 /* The entry in the password file will have the following format 225 * <FQDN of service> = <secret> 226 * <secret> := {HEX}<password in hexadecimal> 227 * 228 * <password> is the actual eDirectory password of the service 229 * Return values: 230 * ERR_NO_MEM - No Memory 231 * ERR_PWD_ZERO - Password has zero length 232 * ERR_PWD_BAD - Passowrd corrupted 233 * ERR_PWD_NOT_HEX - Not a hexadecimal password 234 */ 235 236 int dec_password(struct data pwd, struct data *ret) { 237 int err=0; 238 int i=0, j=0; 239 240 ret->len = 0; 241 ret->value = NULL; 242 243 if (pwd.len == 0) { 244 err = ERR_PWD_ZERO; 245 ret->len = 0; 246 goto cleanup; 247 } 248 249 /* Check if it is a hexadecimal encoded password */ 250 if (pwd.len >= strlen("{HEX}") && 251 strncmp((char *)pwd.value, "{HEX}", strlen("{HEX}")) == 0) { 252 253 if ((pwd.len - strlen("{HEX}")) % 2 != 0) { 254 /* A hexadecimal encoded password should have even length */ 255 err = ERR_PWD_BAD; 256 ret->len = 0; 257 goto cleanup; 258 } 259 ret->value = (unsigned char *)malloc((pwd.len - strlen("{HEX}")) / 2 + 1); 260 if (ret->value == NULL) { 261 err = ERR_NO_MEM; 262 ret->len = 0; 263 goto cleanup; 264 } 265 ret->len = (pwd.len - strlen("{HEX}")) / 2; 266 ret->value[ret->len] = '\0'; 267 for (i = strlen("{HEX}"), j = 0; i < pwd.len; i += 2, j++) { 268 unsigned int k; 269 /* Check if it is a hexadecimal number */ 270 if (isxdigit(pwd.value[i]) == 0 || isxdigit(pwd.value[i + 1]) == 0) { 271 err = ERR_PWD_NOT_HEX; 272 ret->len = 0; 273 goto cleanup; 274 } 275 sscanf((char *)pwd.value + i, "%2x", &k); 276 ret->value[j] = k; 277 } 278 goto cleanup; 279 } else { 280 err = ERR_PWD_NOT_HEX; 281 ret->len = 0; 282 goto cleanup; 283 } 284 285 cleanup: 286 287 if (ret->len == 0) { 288 free(ret->value); 289 ret->value = NULL; 290 } 291 return(err); 292 } 293