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