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