📄 xauth.c
字号:
/* XAUTH related functions * * Copyright (C) 2001-2002 Colubris Networks * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc. * Copyright (C) 2003-2004 Xelerance Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: xauth.c,v 1.35 2004/11/30 15:30:24 mcr Exp $ * * This code originally written by Colubris Networks, Inc. * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation * Porting to 2.x by Sean Mathews *///#ifdef XAUTH#include <stdio.h>#include <string.h>#include <stddef.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/queue.h>#include <crypt.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "oswlog.h"#include "defs.h"#include "state.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h" /* needs id.h */#include "packet.h"#include "demux.h" /* needs packet.h */#include "kernel.h"#include "log.h"#include "cookie.h"#include "server.h"#include "spdb.h"#include "timer.h"#include "rnd.h"#include "ipsec_doi.h" /* needs demux.h and state.h */#include "whack.h"#include "sha1.h"#include "md5.h"#include "crypto.h" /* requires sha1.h and md5.h */#include "paths.h"#include "ike_alg.h"#include "xauth.h"#include "virtual.h"#ifdef HAVE_THREADS#include <pthread.h>#endifstatic stf_statusmodecfg_inI2(struct msg_digest *md);struct paththing pwdfile;extern bool encrypt_message(pb_stream *pbs, struct state *st); /* forward declaration */struct thread_arg{ struct state *st; chunk_t name; chunk_t password; chunk_t connname;};/*** Addresses assigned (usually via MODE_CONFIG) to the Initiator*/struct internal_addr{ ip_address ipaddr; ip_address dns[2]; ip_address wins[2]; };#ifdef XAUTH_USEPAMstaticint xauth_pam_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr);static struct pam_conv conv = { xauth_pam_conv, NULL };/** * Get IP address from a PAM environment variable * * @param pamh An open PAM filehandle * @param var Environment Variable to get the IP address from. Usually IPADDR, DNS[12], WINS[12] * @param addr Pointer to var where you want IP address stored * @return int Return code */staticint get_addr(pam_handle_t *pamh,const char *var,ip_address *addr){ const char *c; int retval; c = pam_getenv(pamh,var); if(c == NULL) { c="0.0.0.0"; } retval = inet_pton(AF_INET,c,(void*) &addr->u.v4.sin_addr.s_addr); addr->u.v4.sin_family = AF_INET; return (retval > 0);}#endifoakley_auth_t xauth_calcbaseauth(oakley_auth_t baseauth){ switch(baseauth) { case HybridInitRSA: case HybridRespRSA: case XAUTHInitRSA: case XAUTHRespRSA: baseauth = OAKLEY_RSA_SIG; break; case XAUTHInitDSS: case XAUTHRespDSS: case HybridInitDSS: case HybridRespDSS: baseauth = OAKLEY_DSS_SIG; break; case XAUTHInitPreShared: case XAUTHRespPreShared: baseauth = OAKLEY_PRESHARED_KEY; break; case XAUTHInitRSAEncryption: case XAUTHRespRSAEncryption: baseauth = OAKLEY_RSA_ENC; break; case XAUTHInitRSARevisedEncryption: case XAUTHRespRSARevisedEncryption: baseauth = OAKLEY_RSA_ENC_REV; break; } return baseauth;} /** * Get inside IP address for a connection * * @param con A currently active connection struct * @param ia internal_addr struct * @return int Return Code */staticint get_internal_addresses(struct connection *con,struct internal_addr *ia){#ifdef XAUTH_USEPAM int retval; char str[48];#endif#ifdef NAT_TRAVERSAL /* only NAT-T code lets us do virtual ends */ if (!isanyaddr(&con->spd.that.client.addr)) { /** assumes IPv4, and also that the mask is ignored */ ia->ipaddr = con->spd.that.client.addr; } else#endif {#ifdef XAUTH_USEPAM if(con->pamh == NULL) { /** Start PAM session, using 'pluto' as our PAM name */ retval = pam_start("pluto", "user", &conv, &con->pamh); memset(ia,0,sizeof(*ia)); if(retval == PAM_SUCCESS) { char buf[IDTOA_BUF]; idtoa(&con->spd.that.id, buf, sizeof(buf)); if (con->spd.that.id.kind == ID_DER_ASN1_DN) { /** Keep only the common name, if one exists */ char *c1, *c2; c1 = strstr(buf, "CN="); if (c1) { c2 = strstr(c1, ", "); if (c2) *c2 = '\0'; memmove(buf, c1+3, strlen(c1) + 1 - 3); } } sprintf(str,"ID=%s", buf); pam_putenv(con->pamh,str); pam_open_session(con->pamh,0); } } if(con->pamh != NULL) { /** Put IP addresses from various variables into our * internal address struct */ get_addr(con->pamh,"IPADDR",&ia->ipaddr); get_addr(con->pamh,"DNS1",&ia->dns[0]); get_addr(con->pamh,"DNS2",&ia->dns[1]); get_addr(con->pamh,"WINS1",&ia->wins[0]); get_addr(con->pamh,"WINS2",&ia->wins[1]); }#endif } return 0;} /** * Compute HASH of Mode Config. * * @param dest * @param start * @param roof * @param st State structure * @return size_t Length of the HASH */size_txauth_mode_cfg_hash(u_char *dest, const u_char *start, const u_char *roof, const struct state *st){ struct hmac_ctx ctx; hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid)); hmac_update(&ctx, start, roof-start); hmac_final(dest, &ctx); DBG(DBG_CRYPT, DBG_log("XAUTH: HASH computed:"); DBG_dump("", dest, ctx.hmac_digest_len)); return ctx.hmac_digest_len;}/** * Mode Config Reply * * Generates a reply stream containing Mode Config information (eg: IP, DNS, WINS) * * @param st State structure * @param resp Type of reply (int) * @param rbody Body of the reply (stream) * @param ap_id ISAMA Identifier * @return stf_status STF_OK or STF_INTERNAL_ERROR */stf_status modecfg_resp(struct state *st ,unsigned int resp ,pb_stream *rbody ,u_int16_t replytype ,bool hackthat ,u_int16_t ap_id){ unsigned char *r_hash_start,*r_hashval; /* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_ATTR); */ { pb_stream hash_pbs; int np = ISAKMP_NEXT_ATTR; if (!out_generic(np, &isakmp_hash_desc, rbody, &hash_pbs)) return STF_INTERNAL_ERROR; r_hashval = hash_pbs.cur; /* remember where to plant value */ if (!out_zero(st->st_oakley.hasher->hash_digest_len, &hash_pbs, "HASH")) return STF_INTERNAL_ERROR; close_output_pbs(&hash_pbs); r_hash_start = (rbody)->cur; /* hash from after HASH payload */ } /* ATTR out */ { struct isakmp_mode_attr attrh; struct isakmp_attribute attr; pb_stream strattr,attrval; int attr_type; struct internal_addr ia; int dns_idx, wins_idx; bool dont_advance; attrh.isama_np = ISAKMP_NEXT_NONE; attrh.isama_type = replytype; attrh.isama_identifier = ap_id; if(!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr)) return STF_INTERNAL_ERROR; zero(&ia); get_internal_addresses(st->st_connection, &ia); if(!isanyaddr(&ia.dns[0])) /* We got DNS addresses, answer with those */ resp |= LELEM(INTERNAL_IP4_DNS); else resp &= ~LELEM(INTERNAL_IP4_DNS); if(!isanyaddr(&ia.wins[0])) /* We got WINS addresses, answer with those */ resp |= LELEM(INTERNAL_IP4_NBNS); else resp &= ~LELEM(INTERNAL_IP4_NBNS); if(hackthat) { if(memcmp(&st->st_connection->spd.that.client.addr ,&ia.ipaddr ,sizeof(ia.ipaddr)) != 0) { /* Make the Internal IP address and Netmask as * that client address */ st->st_connection->spd.that.client.addr = ia.ipaddr; st->st_connection->spd.that.client.maskbits = 32; st->st_connection->spd.that.has_client = TRUE; } } attr_type = 0; dns_idx = 0; wins_idx = 0; while(resp != 0) { dont_advance = FALSE; if(resp & 1) { const unsigned char *byte_ptr; unsigned int len; /* ISAKMP attr out */ attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV; out_struct(&attr, &isakmp_xauth_attribute_desc, &strattr, &attrval); switch(attr_type) { case INTERNAL_IP4_ADDRESS: len = addrbytesptr(&ia.ipaddr, &byte_ptr); out_raw(byte_ptr,len,&attrval,"IP4_addr"); break; case INTERNAL_IP4_NETMASK: { unsigned int mask;#if 0 char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; int t,m=st->st_connection->that.host_addr.maskbit; for(t=0;t<4;t++) { if(m < 8) mask[t] = bits[m]; else mask[t] = 0xff; m -= 8; }#endif if (st->st_connection->spd.this.client.maskbits == 0) mask = 0; else mask = 0xffffffff * 1; out_raw(&mask,4,&attrval,"IP4_mask"); } break; case INTERNAL_IP4_SUBNET: { char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; int t,m=st->st_connection->spd.this.client.maskbits; for(t=0;t<4;t++) { if(m < 8) mask[t] = bits[m]; else mask[t] = 0xff; m -= 8; if(m < 0) m=0; } len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr); out_raw(byte_ptr,len,&attrval,"IP4_subnet"); out_raw(mask,sizeof(mask),&attrval,"IP4_submsk"); } break; case INTERNAL_IP4_DNS: len = addrbytesptr(&ia.dns[dns_idx++], &byte_ptr); out_raw(byte_ptr,len,&attrval,"IP4_dns"); if(dns_idx < 2 && !isanyaddr(&ia.dns[dns_idx])) { dont_advance = TRUE; } break; case INTERNAL_IP4_NBNS: len = addrbytesptr(&ia.wins[wins_idx++], &byte_ptr); out_raw(byte_ptr,len,&attrval,"IP4_wins"); if(wins_idx < 2 && !isanyaddr(&ia.wins[wins_idx])) { dont_advance = TRUE; } break; default: openswan_log("attempt to send unsupported mode cfg attribute %s." , enum_show(&modecfg_attr_names, attr_type)); break; } close_output_pbs(&attrval); } if (!dont_advance) { attr_type++; resp >>= 1; } } close_message(&strattr); } xauth_mode_cfg_hash(r_hashval,r_hash_start,rbody->cur,st); close_message(rbody); encrypt_message(rbody, st); return STF_OK;}/** Set MODE_CONFIG data to client. Pack IP Addresses, DNS, etc... and ship * * @param st State Structure * @return stf_status */stf_status modecfg_send_set(struct state *st){ pb_stream reply,rbody; char buf[256]; /* set up reply */ init_pbs(&reply, buf, sizeof(buf), "ModecfgR1"); st->st_state = STATE_MODE_CFG_R1; /* HDR out */ { struct isakmp_hdr hdr; zero(&hdr); /* default to 0 */ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; hdr.isa_np = ISAKMP_NEXT_HASH; hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG; hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); hdr.isa_msgid = st->st_msgid; if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) { return STF_INTERNAL_ERROR; } }#define MODECFG_SET_ITEM ( LELEM(INTERNAL_IP4_ADDRESS) | LELEM(INTERNAL_IP4_SUBNET) | LELEM(INTERNAL_IP4_NBNS) | LELEM(INTERNAL_IP4_DNS) ) modecfg_resp(st ,MODECFG_SET_ITEM ,&rbody ,ISAKMP_CFG_SET ,TRUE ,0/* XXX ID */);#undef MODECFG_SET_ITEM clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply) , "ModeCfg set"); /* Transmit */ send_packet(st, "ModeCfg set"); /* RETRANSMIT if Main, SA_REPLACE if Aggressive */ if(st->st_event->ev_type != EVENT_RETRANSMIT && st->st_event->ev_type != EVENT_NULL) { delete_event(st); event_schedule(EVENT_RETRANSMIT,EVENT_RETRANSMIT_DELAY_0,st); } return STF_OK;}/** Set MODE_CONFIG data to client. Pack IP Addresses, DNS, etc... and ship * * @param st State Structure * @return stf_status */stf_status modecfg_start_set(struct state *st){ if(st->st_msgid == 0) { /* pick a new message id */ st->st_msgid = generate_msgid(st); } st->hidden_variables.st_modecfg_vars_set = TRUE; return modecfg_send_set(st);}/** Send XAUTH credential request (username + password request) * @param st State * @return stf_status */stf_status xauth_send_request(struct state *st){ pb_stream reply; pb_stream rbody; char buf[256]; u_char *r_hash_start,*r_hashval; /* set up reply */ init_pbs(&reply, buf, sizeof(buf), "xauth_buf"); openswan_log("XAUTH: Sending Username/Password request (XAUTH_R0)"); /* this is the beginning of a new exchange */ st->st_msgid = generate_msgid(st); st->st_state = STATE_XAUTH_R0; /* HDR out */ { struct isakmp_hdr hdr; zero(&hdr); /* default to 0 */ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; hdr.isa_np = ISAKMP_NEXT_HASH; hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG; hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); hdr.isa_msgid = st->st_msgid;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -