/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * gsscred utility * Manages mapping between a security principal name and unix uid */ #include #include #include #include #include #include #include "gsscred.h" #define MAX_STR_LEN 1024 /* * Internal Functions */ static void usage(void); static void addUser(const char *name, const char *oid, const char *userUid, const char *userComment, const char *userMech); static int file_listUsers(const gss_OID mechOid, const char *userUid, char **errDetails); static int listUsers(const char *name, const char *nameTypeOid, const char *uid, const char *mechOid); static int file_removeUsers(const gss_OID mechOid, const char *userUid, char **errDetails); static int removeUsers(const char *name, const char *nameTypeOid, const char *uid, const char *mechOid); /* * Global variables */ static int tableSource; static char *PROG_NAME = NULL; int main(int argc, char *args[]) { char *userName = NULL, *nameTypeOID = NULL, *uid = NULL, *comment = NULL, *mech = NULL, operation = '0'; int c, errflag = 0; extern char *optarg; PROG_NAME = *args; /* set locale and domain for internationalization */ setlocale(LC_ALL, ""); textdomain(TEXT_DOMAIN); if (argc < 2) usage(); /* Process the input arguments */ while ((c = getopt(argc, args, "arln:o:u:m:c:")) != EOF) { switch (c) { case 'n': userName = optarg; break; case 'o': nameTypeOID = optarg; break; case 'u': uid = optarg; break; case 'm': mech = optarg; break; case 'c': comment = optarg; break; case 'a': case 'r': case 'l': operation = c; errflag++; if (errflag > 1) usage(); break; default: usage(); } } /* determine which back-end to use as the gsscred store */ tableSource = gsscred_read_config_file(); /* perform the requested operation */ switch (operation) { case 'a': addUser(userName, nameTypeOID, uid, comment, mech); break; case 'r': removeUsers(userName, nameTypeOID, uid, mech); break; case 'l': listUsers(userName, nameTypeOID, uid, mech); break; default: usage(); } fprintf(stdout, "\n"); return (0); } /* main */ /* * Handles the addition of users to the gsscred table. */ static void addUser(const char *name, const char *nameOidStr, const char *userUid, const char *userComment, const char *mechOidStr) { gss_OID mechOid; gss_buffer_desc fullName = GSS_C_EMPTY_BUFFER, hexBufDesc = GSS_C_EMPTY_BUFFER, hexMechOid = GSS_C_EMPTY_BUFFER; char comment[MAX_STR_LEN+1], hexBuf[MAX_STR_LEN+MAX_STR_LEN+1], hexMechOidBuf[MAX_STR_LEN+1], *commentPtr = NULL, *errDetail = NULL, uidStr[256], *uidPtr; struct passwd *aUser; OM_uint32 minor; int count = 0, retCode; hexMechOid.length = MAX_STR_LEN; hexMechOid.value = (void*)hexMechOidBuf; /* addition of users can only be performed by super users */ if (getuid()) { fprintf(stderr, gettext("\nUser addition requires" " root privileges.")); return; } /* the mechanism OID is required */ if (mechOidStr == NULL) { fprintf(stderr, gettext("\nUnspecified mechanism.")); usage(); } /* Convert from string mechanism Oid to ASN.1 oid and then hex */ if (__gss_mech_to_oid(mechOidStr, &mechOid) != GSS_S_COMPLETE) { fprintf(stderr, gettext("\nInvalid mechanism specified [%s]."), mechOidStr); return; } hexBufDesc.length = mechOid->length; hexBufDesc.value = mechOid->elements; if (!gsscred_AsHex(&hexBufDesc, &hexMechOid)) { fprintf(stderr, gettext("\nInternal error. " "Conversion to hex failed.")); return; } /* * if the name is specified, then do single addition. * Might have to look up the uid. */ if (name != NULL) { hexBufDesc.length = sizeof (hexBuf); hexBufDesc.value = hexBuf; /* build the name as needed */ if (!gsscred_MakeName(mechOid, name, nameOidStr, &fullName)) { fprintf(stderr, gettext("\nError adding user [%s]."), name); return; } /* convert it to hex */ if (!gsscred_AsHex(&fullName, &hexBufDesc)) { gss_release_buffer(&minor, &fullName); fprintf(stderr, gettext("\nInternal error. " "Conversion to hex failed.")); return; } /* might require the lookup of the uid if one not specified */ if (userUid == NULL) { if ((aUser = getpwnam(name)) == NULL) { fprintf(stderr, gettext("\nUnable to obtain password" " information for [%s]."), name); gss_release_buffer(&minor, &fullName); return; } sprintf(uidStr, "%ld", aUser->pw_uid); uidPtr = uidStr; } else uidPtr = (char *)userUid; if (userComment == NULL) { sprintf(comment, "%s, %s", name, mechOidStr); commentPtr = comment; } else commentPtr = (char *)userComment; if (tableSource == GSSCRED_FLAT_FILE) retCode = file_addGssCredEntry(&hexBufDesc, uidPtr, commentPtr, &errDetail); else /* other backends (ldap, dss) coming soon */ retCode = 0; if (!retCode) { fprintf(stderr, gettext("\nError adding user [%s]."), commentPtr); if (errDetail) { fprintf(stderr, "\n%s\n", errDetail); free(errDetail); errDetail = NULL; } } gss_release_buffer(&minor, &fullName); return; } /* * since no name specified, then we will load everyone from * password table. This means that -u and -o options are invalid. * We just ignore it, but we could flag it as error. */ setpwent(); while ((aUser = getpwent()) != NULL) { hexBufDesc.length = sizeof (hexBuf); hexBufDesc.value = hexBuf; if (!gsscred_MakeName(mechOid, aUser->pw_name, nameOidStr, &fullName)) { fprintf(stderr, gettext("\nError adding user [%s]."), aUser->pw_name); continue; } if (!gsscred_AsHex(&fullName, &hexBufDesc)) { gss_release_buffer(&minor, &fullName); fprintf(stderr, gettext("\nInternal error. " "Conversion to hex failed.")); continue; } sprintf(uidStr, "%ld", aUser->pw_uid); sprintf(comment, "%s, %s", aUser->pw_name, mechOidStr); if (tableSource == GSSCRED_FLAT_FILE) retCode = file_addGssCredEntry(&hexBufDesc, uidStr, comment, &errDetail); else retCode = 0; if (!retCode) { fprintf(stderr, gettext("\nError adding user [%s]."), comment); if (errDetail) { fprintf(stderr, "\n%s\n", errDetail); free(errDetail); errDetail = NULL; } } else { count++; if ((count % 50) == 0) fprintf(stdout, gettext("\n[%d] users added..."), count); } gss_release_buffer(&minor, &fullName); } endpwent(); } /* addUser */ /* * Handles the searching of the gsscred table. */ static int listUsers(const char *name, const char *nameOidStr, const char *uidStr, const char *mechOidStr) { GssCredEntry *entryPtr, *entryTmpPtr; char hexMech[256], hexName[(MAX_STR_LEN *2) + 1]; gss_OID anOid = NULL, userMechOid = NULL; gss_OID_set mechSet = NULL; gss_buffer_desc inBufDesc = GSS_C_EMPTY_BUFFER, outBufDesc = GSS_C_EMPTY_BUFFER, searchName = GSS_C_EMPTY_BUFFER; int status = 1, numOfMechs, i; OM_uint32 minor; char *errDetails = NULL; /* Do we need to convert the mechanism oid? */ if (mechOidStr != NULL) { if (__gss_mech_to_oid(mechOidStr, &userMechOid) != GSS_S_COMPLETE) { fprintf(stderr, gettext("\nInvalid mechanism specified [%s]."), mechOidStr); return (0); } inBufDesc.length = userMechOid->length; inBufDesc.value = userMechOid->elements; outBufDesc.length = sizeof (hexMech); outBufDesc.value = hexMech; if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) { fprintf(stderr, gettext("\nInternal error. " "Conversion to hex failed.")); status = 0; goto cleanup; } } /* mechOidStr != NULL */ /* are we retrieving everyone ? or searching by mech ? */ if ((name == NULL && uidStr == NULL && mechOidStr == NULL) || (name == NULL && uidStr == NULL)) { if (tableSource == GSSCRED_FLAT_FILE) { file_listUsers(userMechOid, NULL, &errDetails); if (errDetails) { fprintf(stderr, gettext("\nError searching gsscred" " table [%s]."), errDetails); free(errDetails); errDetails = NULL; return (0); } return (1); } } /* Are we searching by uid or uid and mech? */ if (name == NULL && uidStr != NULL) { if (tableSource == GSSCRED_FLAT_FILE) file_listUsers(userMechOid, uidStr, &errDetails); else { entryPtr = NULL; while (entryPtr != NULL) { fprintf(stdout, "\n%s\t%d\t%s", entryPtr->principal_name, entryPtr->unix_uid, entryPtr->comment); free(entryPtr->principal_name); free(entryPtr->comment); entryTmpPtr = entryPtr->next; free(entryPtr); entryPtr = entryTmpPtr; } } /* check for any errors */ if (errDetails) { fprintf(stderr, gettext("\nError searching gsscred table " "[%s]."), errDetails); free(errDetails); errDetails = NULL; status = 0; } goto cleanup; } /* * We are searching by name; * how many mechs must we check? */ if (mechOidStr == NULL) { if (gss_indicate_mechs(&minor, &mechSet) != GSS_S_COMPLETE) { fprintf(stderr, gettext("\nInternal error. " "GSS-API call failed.")); return (0); } numOfMechs = mechSet->count; } else numOfMechs = 1; /* now look through all the mechs searching */ for (i = 0; i < numOfMechs; i++) { if (mechOidStr == NULL) { anOid = &mechSet->elements[i]; inBufDesc.length = anOid->length; inBufDesc.value = anOid->elements; outBufDesc.length = sizeof (hexMech); outBufDesc.value = hexMech; if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) continue; } else anOid = userMechOid; /* create a gss name */ if (!gsscred_MakeName(anOid, name, nameOidStr, &outBufDesc)) continue; /* now convert it to hex, and find it */ searchName.value = hexName; searchName.length = sizeof (hexName); status = gsscred_AsHex(&outBufDesc, &searchName); free(outBufDesc.value); if (!status) continue; if (tableSource == GSSCRED_FLAT_FILE) file_getGssCredEntry(&searchName, uidStr, &errDetails); else { entryPtr = NULL; /* other backends coming soon */ while (entryPtr != NULL) { fprintf(stdout, "\n%s\t%d\t%s", entryPtr->principal_name, entryPtr->unix_uid, entryPtr->comment); free(entryPtr->principal_name); free(entryPtr->comment); entryTmpPtr = entryPtr->next; free(entryPtr); entryPtr = entryTmpPtr; } } /* any errors to display */ if (errDetails) { fprintf(stderr, gettext("\nError searching gsscred table " "[%s]."), errDetails); free(errDetails); errDetails = NULL; status = 0; } } /* for */ cleanup: if (mechSet != NULL) gss_release_oid_set(&minor, &mechSet); return (status); } /* listUsers */ /* * Performs additional handling while searching for users * stored in the flat file table. */ int file_listUsers(const gss_OID mechOid, const char *unixUid, char **errDetails) { gss_buffer_desc mechBufDesc = GSS_C_EMPTY_BUFFER, mechHexBufDesc = GSS_C_EMPTY_BUFFER; char mechBuf[128], mechHexBuf[256]; if (mechOid != NULL) { /* must make the name header whic contains mech oid */ mechBufDesc.value = (void *) mechBuf; mechBufDesc.length = sizeof (mechBuf); mechHexBufDesc.value = (void*) mechHexBuf; mechHexBufDesc.length = sizeof (mechHexBuf); if ((!gsscred_MakeNameHeader(mechOid, &mechBufDesc)) || (!gsscred_AsHex(&mechBufDesc, &mechHexBufDesc))) { (*errDetails) = strdup( gettext("\nInternal error. " " Conversion to hex failed.")); return (0); } return (file_getGssCredEntry(&mechHexBufDesc, unixUid, errDetails)); } return (file_getGssCredEntry(NULL, unixUid, errDetails)); } /* file_listUsers */ /* * Handles the deletion of users. */ static int removeUsers(const char *name, const char *nameOidStr, const char *uidStr, const char *mechOidStr) { char hexMech[256], hexName[(MAX_STR_LEN *2) + 1], *errDetails = NULL; gss_OID anOid = NULL, userMechOid = NULL; gss_OID_set mechSet = NULL; gss_buffer_desc inBufDesc = GSS_C_EMPTY_BUFFER, outBufDesc = GSS_C_EMPTY_BUFFER, searchName = GSS_C_EMPTY_BUFFER; int status = 0, numOfMechs, i; OM_uint32 minor; /* user deletion can only be performed by super user */ if (getuid()) { fprintf(stderr, gettext("\nUser deletion requires" " root privileges.")); return (0); } /* do we need to convert the mechanism oid? */ if (mechOidStr != NULL) { if (__gss_mech_to_oid(mechOidStr, &userMechOid) != GSS_S_COMPLETE) { fprintf(stderr, gettext("\nInvalid mechanism specified [%s]."), mechOidStr); return (0); } inBufDesc.length = userMechOid->length; inBufDesc.value = userMechOid->elements; outBufDesc.length = sizeof (hexMech); outBufDesc.value = hexMech; if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) { fprintf(stderr, gettext("\nInternal error." " Conversion to hex failed.")); status = 0; goto cleanup; } } /* mechOidStr != NULL */ /* are we deleting the entire table or an entire mech ? */ if (name == NULL && uidStr == NULL) { if (tableSource == GSSCRED_FLAT_FILE) status = file_removeUsers(userMechOid, NULL, &errDetails); else status = 0; /* display any errors */ if (errDetails) { fprintf(stderr, gettext("\nError deleting gsscred entry " "[%s]."), errDetails); free(errDetails); errDetails = NULL; } goto cleanup; } /* are we deleting by uid or uid and mech? */ if (name == NULL && uidStr != NULL) { if (tableSource == GSSCRED_FLAT_FILE) status = file_removeUsers(userMechOid, uidStr, &errDetails); else status = 0; /* check for any errors */ if (errDetails) { fprintf(stderr, gettext("\nError deleting gsscred entry " "[%s]."), errDetails); free(errDetails); errDetails = NULL; } goto cleanup; } /* * We are deleting by name; * how many mechs must we check? */ if (mechOidStr == NULL) { if (gss_indicate_mechs(&minor, &mechSet) != GSS_S_COMPLETE) { fprintf(stderr, gettext("\nInternal error. " "GSS-API call failed.")); status = 0; goto cleanup; } numOfMechs = mechSet->count; } else numOfMechs = 1; /* now look through all the mechs, deleting */ for (i = 0; i < numOfMechs; i++) { if (mechOidStr == NULL) { anOid = &mechSet->elements[i]; inBufDesc.length = anOid->length; inBufDesc.value = anOid->elements; outBufDesc.length = sizeof (hexMech); outBufDesc.value = hexMech; if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) continue; } else anOid = userMechOid; /* create a gss name */ if (!gsscred_MakeName(anOid, name, nameOidStr, &outBufDesc)) continue; /* now convert it to hex, and delete it */ searchName.value = hexName; searchName.length = sizeof (hexName); status = gsscred_AsHex(&outBufDesc, &searchName); free(outBufDesc.value); if (!status) continue; if (tableSource == GSSCRED_FLAT_FILE) status = file_deleteGssCredEntry(&searchName, uidStr, &errDetails); else status = 0; /* check for any errors */ if (errDetails) { fprintf(stderr, gettext("\nError deleting gsscred entry" " [%s]."), errDetails); free(errDetails); errDetails = NULL; } } /* for */ cleanup: if (mechSet != NULL) gss_release_oid_set(&minor, &mechSet); return (status); } /* removeUsers */ /* * Performs additional handling while deleting users * stored in the flat file table. */ int file_removeUsers(const gss_OID mechOid, const char *unixUid, char **errDetails) { gss_buffer_desc mechBufDesc = GSS_C_EMPTY_BUFFER, mechHexBufDesc = GSS_C_EMPTY_BUFFER; char mechBuf[128], mechHexBuf[256]; if (mechOid != NULL) { /* * need to create the buffer header which contains * the mechanism oid. */ mechBufDesc.value = (void*) mechBuf; mechBufDesc.length = sizeof (mechBuf); mechHexBufDesc.value = (void *) mechHexBuf; mechHexBufDesc.length = sizeof (mechHexBuf); if ((!gsscred_MakeNameHeader(mechOid, &mechBufDesc)) || (!gsscred_AsHex(&mechBufDesc, &mechHexBufDesc))) { (*errDetails) = strdup( gettext("\nInternal error." " Conversion to hex failed.")); return (0); } return (file_deleteGssCredEntry(&mechHexBufDesc, unixUid, errDetails)); } return (file_deleteGssCredEntry(NULL, unixUid, errDetails)); } /* file_removeUsers */ /* * Prints the usage string, and terminates. */ static void usage(void) { fprintf(stderr, gettext("\nUsage:\t %s [-n user [-o oid] [-u uid]]" " [-c comment] -m mech -a" "\n\t %s [-n user [-o oid]] [-u uid] [-m mech] -r" "\n\t %s [-n user [-o oid]] [-u uid] [-m mech] -l\n"), PROG_NAME, PROG_NAME, PROG_NAME); exit(1); } /* usage */