diff -ruP freeswan-1.3.orig/pluto/ipsec_doi.c freeswan-1.3/pluto/ipsec_doi.c --- freeswan-1.3.orig/pluto/ipsec_doi.c Tue Feb 8 22:22:22 2000 +++ freeswan-1.3/pluto/ipsec_doi.c Sat Mar 11 13:47:10 2000 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -472,6 +473,97 @@ } } +static char * +exec_preshared_prog(const char *prog, const struct state *st) +{ + static char result[256]; + int child, output_pipe[2]; + + if (0 != pipe(output_pipe)) + { + log("Could not open pipe"); + close(output_pipe[0]); + close(output_pipe[1]); + return NULL; + } + + if ((child = fork())) + { + /* parent */ + if (0 > child) + { + log("Fork failed"); + close(output_pipe[0]); + close(output_pipe[1]); + return NULL; + } + else + { + /* read from child */ + int len; + close(output_pipe[1]); + len = read(output_pipe[0], result, sizeof(result)); + if (len < 0) + { + log("Read from child failed"); + return NULL; + } + result[len] = 0; + { + char *end_line = strchr(result, '\n'); + if (end_line) + { + end_line[0] = 0; + len = end_line - result; + } + } + log("read %d bytes from prog: %s", len, result); + close(output_pipe[0]); + return result; + } + } + else + { + /* child */ + close(output_pipe[0]); + close(0); + dup2(output_pipe[1], 1); + close(output_pipe[1]); + { + const char *argv[4] = {"sh", "-c", prog, NULL}; + char this_addr[10 + SOCKADDR_STRING_SIZE]; + char that_addr[10 + SOCKADDR_STRING_SIZE]; + char nonce_i[8 + 2 + 2*st->st_ni.len + 1]; + char nonce_r[8 + 2 + 2*st->st_ni.len + 1]; + char conn_name[10 + strlen(st->st_connection->name) + 1]; + char hashtype[32]; + //char *env[7] = {this_addr, that_addr, nonce_i, nonce_r, conn_name, hashtype, NULL}; + snprintf(this_addr, sizeof(this_addr), "THIS_ADDR=%s", inet_ntoa(st->st_connection->this.host_addr)); + snprintf(that_addr, sizeof(that_addr), "THAT_ADDR=%s", inet_ntoa(st->st_connection->that.host_addr)); + strcpy(nonce_i, "NONCE_I="); + bytestoa(st->st_ni.ptr, st->st_ni.len, 'x', nonce_i + 8, sizeof(nonce_i) - 8); + strcpy(nonce_r, "NONCE_R="); + bytestoa(st->st_nr.ptr, st->st_nr.len, 'x', nonce_r + 8, sizeof(nonce_r) - 8); + snprintf(conn_name, sizeof(conn_name), "CONN_NAME=%s", st->st_connection->name); + snprintf(hashtype, sizeof(hashtype), "HASHTYPE=%s", enum_name(&oakley_hash_names, st->st_oakley.hash)); + + putenv(this_addr); + putenv(that_addr); + putenv(nonce_i); + putenv(nonce_r); + putenv(conn_name); + putenv(hashtype); + + //execve("/bin/sh", argv, env); + execv("/bin/sh", argv); + exit(errno); + } + } + + // not reached + return NULL; +} + /* SKEYID for preshared keys. * See draft-ietf-ipsec-ike-01.txt 4.1 */ @@ -488,8 +580,69 @@ else { struct hmac_ctx ctx; + + if (!strncmp(pss->ptr, "exec ", sizeof("exec ") - 1)) + { + char *result; + char prog[pss->len + 1 - 5]; + memcpy(prog, pss->ptr + 5, sizeof(prog)); + prog[pss->len - 5] = 0; + log("calling external prog for skeyid: %s", prog); + + if (!(result = exec_preshared_prog(prog, st))) + { + log("skeyid prog execution failure"); + return FALSE; + } + + if (!strncmp("ERROR=", result, sizeof("ERROR=") - 1)) + { + result += sizeof("ERROR=") - 1; + log("skeyid prog reported error: %s", result); + return FALSE; + } - hmac_init_chunk(&ctx, st->st_oakley.hasher, *pss); + if (!strncmp("SKEYID=", result, sizeof("SKEYID=") - 1)) + { + chunk_t* skeyid = &(st->st_skeyid); + freeanychunk(*skeyid); + skeyid->len = st->st_oakley.hasher->hash_digest_len; + skeyid->ptr = alloc_bytes(skeyid->len, "st_skeyid in skeyid_preshared()"); + result += sizeof("SKEYID=") - 1; + return(atobytes(result, strlen(result), skeyid->ptr, skeyid->len, NULL) == NULL); + } + + if (!strncmp("SHARED_SECRET=", result, sizeof("SHARED_SECRET=") - 1)) + { + chunk_t temp_chunk; + char secret[256]; + + result += sizeof("SHARED_SECRET=") - 1; + if (result[0] == '"') + { + result++; + result[strlen(result) - 1] = 0; // strip closing quote + setchunk(temp_chunk, result, strlen(result)); + } + else + { + temp_chunk.ptr = secret; + if (atobytes(result, strlen(result), temp_chunk.ptr, 256, &(temp_chunk.len)) != NULL) + return FALSE; + } + + hmac_init_chunk(&ctx, st->st_oakley.hasher, temp_chunk); + } + else + { + log("skeyid prog result not recognized: %s", result); + return FALSE; + } + } + else + { + hmac_init_chunk(&ctx, st->st_oakley.hasher, *pss); + } hmac_update_chunk(&ctx, st->st_ni); hmac_update_chunk(&ctx, st->st_nr); hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_preshared()", &ctx);