/* Incomplete implementation, single ipv4 addr, service does not work, hints do not work */ int tds_getaddrinfo(const char *node, const char *service, const struct tds_addrinfo *hints, struct tds_addrinfo **res) { struct tds_addrinfo *addr; struct sockaddr_in *sin = NULL; struct hostent *host; in_addr_t ipaddr; char buffer[4096]; struct hostent result; int h_errnop, port = 0; assert(node != NULL); if ((addr = (tds_addrinfo *) calloc(1, sizeof(struct tds_addrinfo))) == NULL) goto Cleanup; if ((sin = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr_in))) == NULL) goto Cleanup; addr->ai_addr = (struct sockaddr *) sin; addr->ai_addrlen = sizeof(struct sockaddr_in); addr->ai_family = AF_INET; if ((ipaddr = inet_addr(node)) == INADDR_NONE) { if ((host = tds_gethostbyname_r(node, &result, buffer, sizeof(buffer), &h_errnop)) == NULL) goto Cleanup; if (host->h_name) addr->ai_canonname = strdup(host->h_name); ipaddr = *(in_addr_t *) host->h_addr; } if (service) { port = atoi(service); if (!port) port = tds_getservice(service); } sin->sin_family = AF_INET; sin->sin_addr.s_addr = ipaddr; sin->sin_port = htons(port); *res = addr; return 0; Cleanup: if (addr != NULL) tds_freeaddrinfo(addr); return -1; }
TDSRET tds_lookup_host_set(const char *servername, struct tds_addrinfo **addr) { struct tds_addrinfo *newaddr; assert(servername != NULL && addr != NULL); if ((newaddr = tds_lookup_host(servername)) != NULL) { if (*addr != NULL) tds_freeaddrinfo(*addr); *addr = newaddr; return TDS_SUCCESS; } return TDS_FAIL; }
/** * Build a GSSAPI packet to send to server * @param tds A pointer to the TDSSOCKET structure managing a client/server operation. * @param packet GSSAPI packet build from function * @return size of packet */ TDSAUTHENTICATION * tds_gss_get_auth(TDSSOCKET * tds) { /* * TODO * There are some differences between this implementation and MS on * - MS use SPNEGO with 3 mechnisms (MS KRB5, KRB5, NTLMSSP) * - MS seems to use MUTUAL flag * - name type is "Service and Instance (2)" and not "Principal (1)" * check for memory leaks * check for errors in many functions * a bit more verbose * dinamically load library ?? */ gss_buffer_desc send_tok; OM_uint32 maj_stat, min_stat; /* same as GSS_KRB5_NT_PRINCIPAL_NAME but do not require .so library */ static gss_OID_desc nt_principal = { 10, (void*) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01" }; const char *server_name; /* Storage for getaddrinfo calls */ struct tds_addrinfo *addrs = NULL; struct tds_gss_auth *auth = (struct tds_gss_auth *) calloc(1, sizeof(struct tds_gss_auth)); if (!auth || !tds->login) return NULL; auth->tds_auth.free = tds_gss_free; auth->tds_auth.handle_next = tds_gss_handle_next; auth->gss_context = GSS_C_NO_CONTEXT; auth->last_stat = GSS_S_COMPLETE; server_name = tds_dstr_cstr(&tds->login->server_host_name); if (strchr(server_name, '.') == NULL) { struct tds_addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_V4MAPPED|AI_ADDRCONFIG|AI_CANONNAME|AI_FQDN; if (!tds_getaddrinfo(server_name, NULL, &hints, &addrs) && addrs->ai_canonname && strchr(addrs->ai_canonname, '.') != NULL) server_name = addrs->ai_canonname; } if (!tds_dstr_isempty(&tds->login->server_spn)) { auth->sname = strdup(tds_dstr_cstr(&tds->login->server_spn)); } else if (tds_dstr_isempty(&tds->login->server_realm_name)) { if (asprintf(&auth->sname, "MSSQLSvc/%s:%d", server_name, tds->login->port) < 0) auth->sname = NULL; } else { if (asprintf(&auth->sname, "MSSQLSvc/%s:%d@%s", server_name, tds->login->port, tds_dstr_cstr(&tds->login->server_realm_name)) < 0) auth->sname = NULL; } if (addrs) tds_freeaddrinfo(addrs); if (auth->sname == NULL) { tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth); return NULL; } tdsdump_log(TDS_DBG_NETWORK, "using kerberos name %s\n", auth->sname); /* * Import the name into target_name. Use send_tok to save * local variable space. */ send_tok.value = auth->sname; send_tok.length = strlen(auth->sname); maj_stat = gss_import_name(&min_stat, &send_tok, &nt_principal, &auth->target_name); switch (maj_stat) { case GSS_S_COMPLETE: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_COMPLETE: gss_import_name completed successfully.\n"); if (TDS_FAILED(tds_gss_continue(tds, auth, GSS_C_NO_BUFFER))) { tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth); return NULL; } break; case GSS_S_BAD_NAMETYPE: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAMETYPE: The input_name_type was unrecognized.\n"); break; case GSS_S_BAD_NAME: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAME: The input_name parameter could not be interpreted as a name of the specified type.\n"); break; case GSS_S_BAD_MECH: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_MECH: The input name-type was GSS_C_NT_EXPORT_NAME, but the mechanism contained within the input-name is not supported.\n"); break; default: tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: unexpected error %d.\n", maj_stat); break; } if (GSS_ERROR(maj_stat)) { tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth); return NULL; } return (TDSAUTHENTICATION *) auth; }