xref: /illumos-gate/usr/src/lib/krb5/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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