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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
35 #include <mechglueP.h>
36 #include "../../cmd/gss/gsscred/gsscred.h"
38 static mutex_t uid_map_lock
= DEFAULTMUTEX
;
39 static int uid_map_opt
= 0;
41 extern int _getgroupsbymember(const char *, gid_t
[], int, int);
43 /* local function used to call a mechanisms pname_to_uid */
44 static OM_uint32
gss_pname_to_uid(OM_uint32
*, const gss_name_t
,
45 const gss_OID
, uid_t
*);
47 static OM_uint32
private_gsscred_expname_to_unix_cred(const gss_buffer_t
,
48 uid_t
*, gid_t
*, gid_t
**, int *);
51 * The gsscred functions will first attempt to call the
52 * mechanism'm pname_to_uid function. In case this function
53 * returns an error or if it is not provided by a mechanism
54 * then the functions will attempt to look up the principal
55 * in the gsscred table.
56 * It is envisioned that the pname_to_uid function will be
57 * provided by only a few mechanism, which may have the principal
58 * name to unix credential mapping inherently present.
62 * Fetch gsscred options from conf file.
65 get_conf_options(int *uid_map
)
70 static char *conffile
= "/etc/gss/gsscred.conf";
73 if ((defp
= defopen_r(conffile
)) != NULL
) {
74 flags
= defcntl_r(DC_GETFLAGS
, 0, defp
);
76 TURNOFF(flags
, DC_CASE
);
77 (void) defcntl_r(DC_SETFLAGS
, flags
, defp
);
79 if ((ptr
= defread_r("SYSLOG_UID_MAPPING=", defp
)) != NULL
&&
80 strcasecmp("yes", ptr
) == 0) {
93 (void) mutex_lock(&uid_map_lock
);
95 (void) mutex_unlock(&uid_map_lock
);
103 (void) mutex_lock(&uid_map_lock
);
105 (void) mutex_unlock(&uid_map_lock
);
110 * This routine accepts a name in export name format and retrieves
111 * unix credentials associated with it.
115 gsscred_expname_to_unix_cred_ext(
116 const gss_buffer_t expName
,
124 OM_uint32 minor
, major
;
125 const char *mechStr
= NULL
;
126 char *nameStr
= NULL
;
127 char *whoami
= "gsscred_expname_to_unix_cred";
128 gss_buffer_desc namebuf
;
129 int debug
= get_uid_map_opt();
132 return (GSS_S_CALL_INACCESSIBLE_WRITE
);
135 return (GSS_S_CALL_INACCESSIBLE_READ
);
137 /* first check the mechanism for the mapping */
138 if (gss_import_name(&minor
, expName
, (gss_OID
)GSS_C_NT_EXPORT_NAME
,
139 &intName
) == GSS_S_COMPLETE
) {
142 gss_union_name_t uintName
= (gss_union_name_t
)intName
;
144 if (uintName
->mech_type
)
145 mechStr
= __gss_oid_to_mech(
146 uintName
->mech_type
);
148 major
= gss_display_name(&minor
, intName
,
150 if (major
== GSS_S_COMPLETE
) {
151 nameStr
= strdup(namebuf
.value
);
152 (void) gss_release_buffer(&minor
, &namebuf
);
157 major
= gss_pname_to_uid(&minor
, intName
,
159 if (major
== GSS_S_COMPLETE
) {
162 syslog(LOG_AUTH
|LOG_DEBUG
,
163 "%s: mech provided local name"
164 " mapping (%s, %s, %d)", whoami
,
165 mechStr
? mechStr
: "<null>",
166 nameStr
? nameStr
: "<null>",
171 (void) gss_release_name(&minor
, &intName
);
172 if (gids
&& gidsLen
&& gidOut
)
173 return (gss_get_group_info(*uidOut
,
174 gidOut
, gids
, gidsLen
));
175 return (GSS_S_COMPLETE
);
179 (void) gss_release_name(&minor
, &intName
);
183 * we fall back onto the gsscred table to provide the mapping
184 * start by making sure that the expName is an export name buffer
186 major
= private_gsscred_expname_to_unix_cred(expName
, uidOut
, gidOut
,
189 if (debug
&& major
== GSS_S_COMPLETE
) {
190 syslog(LOG_AUTH
|LOG_DEBUG
,
191 "%s: gsscred tbl provided"
192 " local name mapping (%s, %s, %d)",
194 mechStr
? mechStr
: "<unknown>",
195 nameStr
? nameStr
: "<unknown>",
199 syslog(LOG_AUTH
|LOG_DEBUG
,
200 "%s: gsscred tbl could NOT"
201 " provide local name mapping (%s, %s)",
203 mechStr
? mechStr
: "<unknown>",
204 nameStr
? nameStr
: "<unknown>");
210 } /* gsscred_expname_to_unix_cred */
213 gsscred_expname_to_unix_cred(
214 const gss_buffer_t expName
,
220 return (gsscred_expname_to_unix_cred_ext(expName
, uidOut
, gidOut
, gids
,
225 static const char *expNameTokId
= "\x04\x01";
226 static const int expNameTokIdLen
= 2;
228 * private routine added to be called from gsscred_name_to_unix_cred
229 * and gsscred_expName_to_unix_cred.
232 private_gsscred_expname_to_unix_cred(expName
, uidOut
, gidOut
, gids
, gidsLen
)
233 const gss_buffer_t expName
;
240 if (expName
->length
< expNameTokIdLen
||
241 (memcmp(expName
->value
, expNameTokId
, expNameTokIdLen
) != 0))
242 return (GSS_S_DEFECTIVE_TOKEN
);
244 if (!gss_getGssCredEntry(expName
, uidOut
))
245 return (GSS_S_FAILURE
);
247 /* did caller request group info also ? */
248 if (gids
&& gidsLen
&& gidOut
)
249 return (gss_get_group_info(*uidOut
, gidOut
, gids
, gidsLen
));
251 return (GSS_S_COMPLETE
);
255 * Return a string of the authenticated name.
256 * It's a bit of hack/workaround/longroad but the current intName
257 * passed to gss_display_name insists on returning an empty string.
259 * Caller must free string memory.
263 const gss_name_t intName
,
264 const gss_OID mechType
)
267 gss_buffer_desc expName
= GSS_C_EMPTY_BUFFER
;
268 OM_uint32 major
, minor
;
269 gss_name_t canonName
;
271 gss_buffer_desc namebuf
;
273 if (major
= gss_canonicalize_name(&minor
, intName
,
274 mechType
, &canonName
))
277 major
= gss_export_name(&minor
, canonName
, &expName
);
278 (void) gss_release_name(&minor
, &canonName
);
282 if (gss_import_name(&minor
, &expName
,
283 (gss_OID
)GSS_C_NT_EXPORT_NAME
,
284 &iName
) == GSS_S_COMPLETE
) {
286 major
= gss_display_name(&minor
, iName
, &namebuf
, NULL
);
287 if (major
== GSS_S_COMPLETE
) {
291 s
= strdup(namebuf
.value
);
293 (void) gss_release_buffer(&minor
, &namebuf
);
294 (void) gss_release_buffer(&minor
, &expName
);
295 (void) gss_release_buffer(&minor
, (gss_buffer_t
)iName
);
298 (void) gss_release_buffer(&minor
, (gss_buffer_t
)iName
);
301 (void) gss_release_buffer(&minor
, &expName
);
306 * This routine accepts a name in gss internal name format together with
307 * a mechanim OID and retrieves a unix credentials for that entity.
310 gsscred_name_to_unix_cred_ext(
311 const gss_name_t intName
,
312 const gss_OID mechType
,
319 gss_name_t canonName
;
320 gss_buffer_desc expName
= GSS_C_EMPTY_BUFFER
;
321 OM_uint32 major
, minor
;
322 int debug
= get_uid_map_opt();
325 char *whoami
= "gsscred_name_to_unix_cred";
326 gss_buffer_desc namebuf
;
328 if (intName
== NULL
|| mechType
== NULL
)
329 return (GSS_S_CALL_INACCESSIBLE_READ
);
332 return (GSS_S_CALL_INACCESSIBLE_WRITE
);
334 mechStr
= __gss_oid_to_mech(mechType
);
336 /* first try the mechanism provided mapping */
337 if (try_mech
&& gss_pname_to_uid(&minor
, intName
, mechType
, uidOut
)
341 char *s
= make_name_str(intName
, mechType
);
342 syslog(LOG_AUTH
|LOG_DEBUG
,
343 "%s: mech provided local name"
344 " mapping (%s, %s, %d)", whoami
,
345 mechStr
? mechStr
: "<null>",
351 if (gids
&& gidsLen
&& gidOut
)
352 return (gss_get_group_info(*uidOut
, gidOut
, gids
,
354 return (GSS_S_COMPLETE
);
357 * falling back onto the gsscred table to provide the mapping
358 * start by canonicalizing the passed in name and then export it
360 if (major
= gss_canonicalize_name(&minor
, intName
,
361 mechType
, &canonName
))
364 major
= gss_export_name(&minor
, canonName
, &expName
);
365 (void) gss_release_name(&minor
, &canonName
);
369 major
= private_gsscred_expname_to_unix_cred(&expName
, uidOut
, gidOut
,
376 char *nameStr
= NULL
;
378 if (gss_import_name(&minor
, &expName
,
379 (gss_OID
)GSS_C_NT_EXPORT_NAME
, &iName
) == GSS_S_COMPLETE
) {
381 maj
= gss_display_name(&minor
, iName
, &namebuf
,
383 (void) gss_release_buffer(&minor
, (gss_buffer_t
)iName
);
384 if (maj
== GSS_S_COMPLETE
) {
385 nameStr
= strdup(namebuf
.value
);
386 (void) gss_release_buffer(&minor
, &namebuf
);
390 if (major
== GSS_S_COMPLETE
)
391 syslog(LOG_AUTH
|LOG_DEBUG
,
392 "%s: gsscred tbl provided"
393 " local name mapping (%s, %s, %d)",
395 mechStr
? mechStr
: "<unknown>",
396 nameStr
? nameStr
: "<unknown>",
399 syslog(LOG_AUTH
|LOG_DEBUG
,
400 "%s: gsscred tbl could NOT"
401 " provide local name mapping (%s, %s)",
403 mechStr
? mechStr
: "<unknown>",
404 nameStr
? nameStr
: "<unknown>");
409 (void) gss_release_buffer(&minor
, &expName
);
411 } /* gsscred_name_to_unix_cred */
415 gsscred_name_to_unix_cred(
416 const gss_name_t intName
,
417 const gss_OID mechType
,
423 return (gsscred_name_to_unix_cred_ext(intName
, mechType
,
424 uidOut
, gidOut
, gids
, gidsLen
, 1));
430 * This routine accepts a unix uid, and retrieves the group id
431 * and supplamentery group ids for that uid.
432 * Callers should be aware that the supplamentary group ids
433 * array may be empty even when this function returns success.
436 gss_get_group_info(uid
, gidOut
, gids
, gidsLen
)
445 /* check for output parameters */
446 if (gidOut
== NULL
|| gids
== NULL
|| gidsLen
== NULL
)
447 return (GSS_S_CALL_INACCESSIBLE_WRITE
);
452 /* determine maximum number of groups possible */
453 maxgroups
= sysconf(_SC_NGROUPS_MAX
);
457 if ((pw
= getpwuid(uid
)) == NULL
)
458 return (GSS_S_FAILURE
);
461 * we allocate for the maximum number of groups
462 * we do not reclaim the space when the actual number
463 * is lower, just set the size approprately.
465 *gids
= (gid_t
*)calloc(maxgroups
, sizeof (gid_t
));
467 return (GSS_S_FAILURE
);
469 *gidOut
= pw
->pw_gid
;
470 (*gids
)[0] = pw
->pw_gid
;
471 *gidsLen
= _getgroupsbymember(pw
->pw_name
, *gids
, maxgroups
, 1);
473 * we will try to remove the duplicate entry from the groups
474 * array. This can cause the group array to be empty.
480 return (GSS_S_FAILURE
);
481 } else if (*gidsLen
== 1) {
486 /* length is atleast 2 */
487 *gidsLen
= *gidsLen
-1;
488 (*gids
)[0] = (*gids
)[*gidsLen
];
491 return (GSS_S_COMPLETE
);
492 } /* gss_get_group_info */
496 gss_pname_to_uid(minor
, name
, mech_type
, uidOut
)
498 const gss_name_t name
;
499 const gss_OID mech_type
;
503 gss_union_name_t intName
;
504 gss_name_t mechName
= NULL
;
505 OM_uint32 major
, tmpMinor
;
508 return (GSS_S_CALL_INACCESSIBLE_WRITE
);
513 return (GSS_S_CALL_INACCESSIBLE_WRITE
);
516 return (GSS_S_CALL_INACCESSIBLE_READ
);
518 intName
= (gss_union_name_t
)name
;
520 if (mech_type
!= NULL
)
521 mech
= __gss_get_mechanism(mech_type
);
524 * if this is a MN, then try using the mech
525 * from the name; otherwise ask for default
527 mech
= __gss_get_mechanism(intName
->mech_type
);
530 if (mech
== NULL
|| mech
->pname_to_uid
== NULL
)
531 return (GSS_S_UNAVAILABLE
);
533 /* may need to import the name if this is not MN */
534 if (intName
->mech_type
== NULL
) {
535 major
= __gss_import_internal_name(minor
,
538 if (major
!= GSS_S_COMPLETE
)
541 mechName
= intName
->mech_name
;
544 /* now call the mechanism's pname function to do the work */
545 major
= mech
->pname_to_uid(mech
->context
, minor
, mechName
, uidOut
);
547 if (intName
->mech_name
!= mechName
)
548 (void) __gss_release_internal_name(&tmpMinor
, &mech
->mech_type
,
552 } /* gss_pname_to_uid */