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