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
krb5_ldap_readpassword(context,ldap_context,password)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
tohex(in,ret)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
dec_password(struct data pwd,struct data * ret)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