4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
37 * Manages mapping between a security principal name and unix uid.
38 * Implementation file for the file based gsscred utility.
41 #define MAX_ENTRY_LEN 1024
43 static const char credFile
[] = "/etc/gss/gsscred_db";
44 static const char credFileTmp
[] = "/etc/gss/gsscred_db.tmp";
45 static const int expNameTokIdLen
= 2;
46 static const int mechOidLenLen
= 2;
47 static const int krb5OidTagLen
= 1;
48 static const int krb5OidLenLen
= 1;
49 static const int nameLen
= 4;
50 static const int krb5OidLen
= 9;
53 * Multiply by two given that the token has already gone through hex string
56 #define NAME_OFFSET (expNameTokIdLen + mechOidLenLen + krb5OidTagLen + \
57 krb5OidLenLen + krb5OidLen + nameLen) * 2
59 static int matchEntry(const char *entry
, const gss_buffer_t name
,
60 const char *uid
, uid_t
*uidOut
);
63 * file_addGssCredEntry
65 * Adds a new entry to the gsscred table.
66 * Does not check for duplicate entries.
68 int file_addGssCredEntry(const gss_buffer_t hexName
, const char *uid
,
69 const char *comment
, char **errDetails
)
74 if ((fp
= fopen(credFile
, "a")) == NULL
) {
76 (void) snprintf(tmpBuf
, sizeof (tmpBuf
),
77 gettext("Unable to open gsscred file [%s]"),
79 *errDetails
= strdup(tmpBuf
);
85 "%s\t%s\t%s\n", (char *)hexName
->value
, uid
, comment
);
88 } /* ******* file_addGssCredEntry ****** */
93 * file_getGssCredEntry
95 * Searches the file for the file matching the name. Since the name
96 * contains a mechanism identifier, to search for all names for a given
97 * mechanism just supply the mechanism portion in the name buffer.
98 * To search by uid only, supply a non-null value of uid.
100 int file_getGssCredEntry(const gss_buffer_t name
, const char *uid
,
104 char entry
[MAX_ENTRY_LEN
+1];
106 if ((fp
= fopen(credFile
, "r")) == NULL
) {
109 (void) snprintf(entry
, sizeof (entry
),
110 gettext("Unable to open gsscred file [%s]"),
112 *errDetails
= strdup(entry
);
118 /* go through the file in sequential order */
119 while (fgets(entry
, MAX_ENTRY_LEN
, fp
) != NULL
) {
120 /* is there any search criteria */
121 if (name
== NULL
&& uid
== NULL
) {
122 (void) fprintf(stdout
, "%s", entry
);
126 if (matchEntry(entry
, name
, uid
, NULL
))
127 (void) fprintf(stdout
, "%s", entry
);
133 } /* file_getGssCredEntry */
138 * GSS entry point for retrieving user uid information.
139 * We need to go through the entire file to ensure that
140 * the last matching entry is retrieved - this is because
141 * new entries are added to the end, and in case of
142 * duplicates we want to get the latest entry.
145 file_getGssCredUid(const gss_buffer_t expName
, uid_t
*uidOut
)
148 char entry
[MAX_ENTRY_LEN
+1];
151 if ((fp
= fopen(credFile
, "r")) == NULL
)
154 /* go through the entire file in sequential order */
155 while (fgets(entry
, MAX_ENTRY_LEN
, fp
) != NULL
) {
156 if (matchEntry(entry
, expName
, NULL
, uidOut
)) {
163 } /* file_getGssCredUid */
169 * file_deleteGssCredEntry
171 * removes entries form file that match the delete criteria
173 int file_deleteGssCredEntry(const gss_buffer_t name
, const char *uid
,
177 char entry
[MAX_ENTRY_LEN
+1];
180 /* are we deleting everyone? */
181 if (name
== NULL
&& uid
== NULL
) {
183 if ((fp
= fopen(credFile
, "w")) == NULL
) {
186 (void) snprintf(entry
, sizeof (entry
),
187 gettext("Unable to open gsscred"
190 *errDetails
= strdup(entry
);
199 /* selective delete - might still be everyone */
200 if ((fp
= fopen(credFile
, "r")) == NULL
) {
203 (void) snprintf(entry
, sizeof (entry
),
204 gettext("Unable to open gsscred file [%s]"),
206 *errDetails
= strdup(entry
);
211 /* also need to open temp file */
212 if ((tempFp
= fopen(credFileTmp
, "w")) == NULL
) {
214 (void) snprintf(entry
, sizeof (entry
),
215 gettext("Unable to open gsscred temporary"
218 *errDetails
= strdup(entry
);
225 /* go through all the entries sequentially removing ones that match */
226 while (fgets(entry
, MAX_ENTRY_LEN
, fp
) != NULL
) {
228 if (!matchEntry(entry
, name
, uid
, NULL
))
229 (void) fputs(entry
, tempFp
);
233 (void) fclose(tempFp
);
236 /* now make the tempfile the gsscred file */
237 (void) rename(credFileTmp
, credFile
);
238 (void) unlink(credFileTmp
);
241 *errDetails
= strdup(gettext("No users found"));
245 } /* file_deleteGssCredEntry */
253 * checks if the specified entry matches the supplied criteria
254 * returns 1 if yes, 0 if no
255 * uidOut value can be used to retrieve the uid from the entry
256 * when the uid string is passed in, the uidOut value is not set
258 static int matchEntry(const char *entry
, const gss_buffer_t name
,
259 const char *uid
, uid_t
*uidOut
)
261 char fullEntry
[MAX_ENTRY_LEN
+1], *item
, *item_buf
, *name_buf
;
262 char dilims
[] = "\t \n";
264 * item_len is the length of the token in the gsscred_db.
265 * name_len is the length of the token passed to this function.
267 int item_len
, name_len
;
269 * This is the hex encoding of the beginning of all exported name
270 * tokens for the Kerberos V mechanism. We need this to detect old,
271 * incorrectly exported name tokens; see below.
273 char *krb5_ntok_prefix
= "0401000B06092A864886F712010202";
275 * This is the hex encoded GSS_C_NT_USER_NAME OID, needed for the same
276 * reason as krb5_ntok_prefix.
278 char *gss_u_name
= "2A864886F71201020101";
280 if (entry
== NULL
|| isspace(*entry
))
283 /* save the entry since strtok will chop it up */
284 (void) strcpy(fullEntry
, entry
);
286 if ((item
= strtok(fullEntry
, dilims
)) == NULL
)
289 /* do we need to search the name */
292 item_len
= strlen(item
);
293 name_len
= name
->length
;
294 name_buf
= name
->value
;
296 /* we can match the prefix of the string */
297 if (item_len
< name_len
)
300 if (strncmp(item
, name
->value
, name_len
) != 0) {
303 * The following section is needed in order to detect
304 * two existing errant formats in the gsscred db.
306 * 1. Exported names that have a trailing null byte
307 * ("00" in two hex characters) with the name length
308 * incremented to account for the extra null byte.
310 * 2. Exported names that have the name type length
311 * and name type OID prepended to the exported name.
314 if (strncmp(name
->value
, krb5_ntok_prefix
,
315 strlen(krb5_ntok_prefix
)) != 0)
318 if (strncmp(item
, krb5_ntok_prefix
,
319 strlen(krb5_ntok_prefix
)) != 0)
322 if ((item_buf
= strstr(item
, gss_u_name
)) == NULL
)
325 item_buf
+= strlen(gss_u_name
);
327 name_buf
+= NAME_OFFSET
;
329 if ((strlen(item_buf
) != strlen(name_buf
)) &&
330 (strncmp(item_buf
+ (strlen(item_buf
) - 2), "00", 2)
335 * Here we compare the end of name_len, given
336 * that item_len could have two extra "00"
337 * representing the null byte.
339 if (strncmp(item_buf
, name_buf
, name_len
- NAME_OFFSET
)
344 * We only strncmp() so we could check for old,
345 * broken exported name tokens for the krb5 mech.
346 * For any other exported name tokens we want exact
349 if (item_len
!= name_len
)
352 /* do we need to check the uid - if not then we found it */
354 /* do we ned to parse out the uid ? */
356 if ((item
= strtok(NULL
, dilims
)) == NULL
)
358 *uidOut
= atol(item
);
363 /* continue with checking the uid */
369 /* get the next token from the string - the uid */
370 if ((item
= strtok(NULL
, dilims
)) == NULL
)
373 if (strcmp(item
, uid
) == 0)
377 } /* ******* matchEntry ****** */