VGAuthError ServiceStartUserConnection(const char *userName, char **pipeName) { ServiceConnection *userConn; VGAuthError err = VGAUTH_E_OK; gboolean connReuse = FALSE; gboolean bRet; /* Check if we can find the listening connection in the map */ userConn = ServiceLookupListenConnection(userName); if (userConn) { connReuse = TRUE; } #if LISTENCONN_NO_REUSE // remove from hash table which will call ServiceConnectionShutdown() (void) g_hash_table_remove(listenConnectionMap, userName); #else bRet = UsercheckUserExists(userName); if (userConn) { if (bRet) { /* * If we have a cached conn -- and the user is still around (seems * like a weird corner case, but the 'deleted user' unit test hits * this) -- reuse. */ *pipeName = g_strdup(userConn->pipeName); goto done; } else { /* * Have a conn, but can't find the user -- clean up before we make * a new conn. This can happen if the service is hit by a network * glitch or the LDAP bug (see usercheck.c for details). * * Throw out the old, let it (try) to make a new. If its the * LDAP bug, the listen will succeed, and we don't want to * end up with two userConn's for the same user. */ Debug("%s: Already have a connection for user '%s', but the user " "check failed, so tearing down the connection and trying " "to rebuild\n", __FUNCTION__, userName); (void) g_hash_table_remove(listenConnectionMap, userName); // fall thru and let a new conn get created } } #endif err = ServiceCreateUserConnection(userName, &userConn); if (err != VGAUTH_E_OK) { goto done; } err = (* startListeningIOFunc) (userConn); if (err != VGAUTH_E_OK) { goto done; } *pipeName = g_strdup(userConn->pipeName); /* Insert the new connection into the map */ ServiceMapListenConnection(userName, userConn); done: if (err != VGAUTH_E_OK && userConn) { if (connReuse) { VGAUTH_LOG_DEBUG("%s: removing dead userConn for %s from hashtable", __FUNCTION__, userName); (void) g_hash_table_remove(listenConnectionMap, userName); } else { VGAUTH_LOG_DEBUG("%s: removing failed userConn for %s", __FUNCTION__, userName); ServiceConnectionShutdown(userConn); } } else if (NULL != userConn) { g_get_current_time(&userConn->lastUse); } return err; }
VGAuthError ServiceVerifyAndCheckTrustCertChainForSubject(int numCerts, const char **pemCertChain, const char *userName, ServiceSubject *subj, char **userNameOut, ServiceAliasInfo **verifyAi) { VGAuthError err; int numMapped = 0; ServiceMappedAlias *maList = NULL; int numStoreCerts = 0; ServiceAlias *aList = NULL; int matchIdIdx = -1; int matchSiIdx = -1; ServiceAliasInfo *ai; char **trustedCerts = NULL; int numTrusted = 0; char **untrustedCerts = NULL; int numUntrusted = 0; char *queryUserName = NULL; char *leafCert = NULL; gboolean foundTrusted; int i; int j; int k; *userNameOut = NULL; *verifyAi = NULL; ASSERT(subj); ASSERT(numCerts > 0); /* * If we have no userName, look through the mapping file for a match * from the cert chain. */ if (NULL == userName || *userName == '\0') { err = ServiceAliasQueryMappedAliases(&numMapped, &maList); if (VGAUTH_E_OK != err) { goto done; } if (0 == numMapped) { /* * No username, no mapped certs, no chance. */ Debug("%s: no mapping entries or userName\n", __FUNCTION__); err = VGAUTH_E_AUTHENTICATION_DENIED; goto done; } /* * Search for a match in the mapped store. */ for (i = 0; i < numCerts; i++) { for (j = 0; j < numMapped; j++) { if (ServiceComparePEMCerts(pemCertChain[i], maList[j].pemCert)) { /* * Make sure we don't have multiple matches with different users. * Two possible scenarios that can trigger this: * - the mapping file could be inconsistent * - the chain coming in could have more than one cert that * exists in the mapping file, belonging to different users */ if ((NULL != queryUserName) && g_strcmp0(queryUserName, maList[j].userName) != 0) { Warning("%s: found more than one user in map file chain\n", __FUNCTION__); err = VGAUTH_E_MULTIPLE_MAPPINGS; goto done; } for (k = 0; k < maList[j].num; k++) { if ((maList[j].subjects[k].type == SUBJECT_TYPE_ANY) || ServiceAliasIsSubjectEqual(subj->type, maList[j].subjects[k].type, subj->name, maList[j].subjects[k].name)) { queryUserName = g_strdup(maList[j].userName); break; } } } } } /* * Subject went unmatched, so fail. */ if (NULL == queryUserName) { Debug("%s: no matching subject found in mapping file\n", __FUNCTION__); err = VGAUTH_E_AUTHENTICATION_DENIED; goto done; } } else { queryUserName = g_strdup(userName); } /* * Make sure the user exists -- Query supports deleted users * to allow for cleanup. */ if (!UsercheckUserExists(queryUserName)) { Debug("%s: User '%s' doesn't exist\n", __FUNCTION__, queryUserName); err = VGAUTH_E_AUTHENTICATION_DENIED; goto done; } err = ServiceAliasQueryAliases(queryUserName, &numStoreCerts, &aList); if (VGAUTH_E_OK != err) { goto done; } /* * Split the incoming chain into trusted and untrusted certs */ for (i = 0; i < numCerts; i++) { int foundAnyIdx; int foundSubjectIdx; foundTrusted = FALSE; for (j = 0; j < numStoreCerts; j++) { if (ServiceComparePEMCerts(pemCertChain[i], aList[j].pemCert)) { /* * Remember the root cert, so we can return its AliasInfo * if all checks out. */ matchIdIdx = j; foundAnyIdx = -1; foundSubjectIdx = -1; for (k = 0; k < aList[j].num; k++) { if (aList[j].infos[k].type == SUBJECT_TYPE_ANY) { foundAnyIdx = k; } else if (ServiceAliasIsSubjectEqual(subj->type, aList[j].infos[k].type, subj->name, aList[j].infos[k].name)) { foundSubjectIdx = k; } } if ((foundSubjectIdx >= 0) || (foundAnyIdx >= 0)) { numTrusted++; trustedCerts = g_realloc(trustedCerts, numTrusted * sizeof(*trustedCerts)); trustedCerts[numTrusted - 1] = g_strdup(pemCertChain[i]); foundTrusted = TRUE; /* * Remember the matching ai, so we can return its comment * if all checks out. Note that a specific subject match takes * precendence over an ANY match. */ matchSiIdx = (foundSubjectIdx >= 0) ? foundSubjectIdx : foundAnyIdx; } } } if (!foundTrusted) { numUntrusted++; untrustedCerts = g_realloc(untrustedCerts, numUntrusted * sizeof(*untrustedCerts)); untrustedCerts[numUntrusted - 1] = g_strdup(pemCertChain[i]); } } /* * Make sure we have at least one trusted cert. */ if (numTrusted == 0) { err = VGAUTH_E_AUTHENTICATION_DENIED; Debug("%s: No trusted certs in chain\n", __FUNCTION__); goto done; } /* * Pull out the leaf -- it should be either the first trusted * or untrusted cert */ if (g_strcmp0(pemCertChain[0], trustedCerts[0]) == 0) { numTrusted--; leafCert = trustedCerts[0]; memmove(trustedCerts, &(trustedCerts[1]), sizeof(*trustedCerts) * numTrusted); } else if (g_strcmp0(pemCertChain[0], untrustedCerts[0]) == 0) { numUntrusted--; leafCert = untrustedCerts[0]; memmove(untrustedCerts, &(untrustedCerts[1]), sizeof(*untrustedCerts) * numUntrusted); } else { ASSERT(0); } err = CertVerify_CertChain(leafCert, numUntrusted, (const char **) untrustedCerts, numTrusted, (const char **) trustedCerts); if (VGAUTH_E_OK != err) { goto done; } Debug("%s: cert chain successfully validated", __FUNCTION__); /* * Save off AliasInfo. * * XXX unclear on what should be done here if we have multiple * trusted certs in the alias store. For now, use the root-most * (last found). */ ai = g_malloc0(sizeof(ServiceAliasInfo)); ASSERT(matchIdIdx >= 0 && matchSiIdx >= 0); ai->type = aList[matchIdIdx].infos[matchSiIdx].type; ai->name = g_strdup(aList[matchIdIdx].infos[matchSiIdx].name); ai->comment = g_strdup(aList[matchIdIdx].infos[matchSiIdx].comment); *verifyAi = ai; *userNameOut = queryUserName; queryUserName = NULL; done: ServiceAliasFreeMappedAliasList(numMapped, maList); ServiceAliasFreeAliasList(numStoreCerts, aList); for (i = 0; i < numTrusted; i++) { g_free(trustedCerts[i]); } g_free(trustedCerts); for (i = 0; i < numUntrusted; i++) { g_free(untrustedCerts[i]); } g_free(untrustedCerts); g_free(leafCert); g_free(queryUserName); return err; }