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