1c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh/* $NetBSD: rsalist.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */ 20a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 30a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* Id: rsalist.c,v 1.3 2004/11/08 12:04:23 ludvigm Exp */ 40a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 50a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* 60a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. 70a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs 80a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * All rights reserved. 90a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Redistribution and use in source and binary forms, with or without 110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * modification, are permitted provided that the following conditions 120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * are met: 130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 1. Redistributions of source code must retain the above copyright 140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * notice, this list of conditions and the following disclaimer. 150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 2. Redistributions in binary form must reproduce the above copyright 160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * notice, this list of conditions and the following disclaimer in the 170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * documentation and/or other materials provided with the distribution. 180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 3. Neither the name of the project nor the names of its contributors 190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * may be used to endorse or promote products derived from this software 200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * without specific prior written permission. 210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * SUCH DAMAGE. 330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang */ 340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "config.h" 360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <stdio.h> 380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <string.h> 390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/types.h> 410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/queue.h> 420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/socket.h> 430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <netdb.h> 440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/bn.h> 460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/rsa.h> 470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "misc.h" 490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "plog.h" 500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "sockmisc.h" 510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "rsalist.h" 520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "genlist.h" 530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "remoteconf.h" 540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "crypto_openssl.h" 550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifndef LIST_FIRST 570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#define LIST_FIRST(head) ((head)->lh_first) 580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif 590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifndef LIST_NEXT 610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#define LIST_NEXT(elm, field) ((elm)->field.le_next) 620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif 630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* from prsa_tok.l */ 650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint prsa_parse_file(struct genlist *list, const char *fname, enum rsa_key_type type); 660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint 680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_key_insert(struct genlist *list, struct netaddr *src, 690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct netaddr *dst, RSA *rsa) 700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct rsa_key *rsa_key; 720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang rsa_key = calloc(sizeof(struct rsa_key), 1); 740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang rsa_key->rsa = rsa; 750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (src) 770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang rsa_key->src = src; 780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang else 790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang rsa_key->src = calloc(sizeof(*rsa_key->src), 1); 800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (dst) 820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang rsa_key->dst = dst; 830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang else 840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang rsa_key->dst = calloc(sizeof(*rsa_key->dst), 1); 850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang genlist_append(list, rsa_key); 870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return 0; 890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstatic void * 920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_key_dump_one(void *entry, void *arg) 930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct rsa_key *key = entry; 950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang plog(LLV_DEBUG, LOCATION, NULL, "Entry %s\n", 970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang naddrwop2str_fromto("%s -> %s", key->src, 980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang key->dst)); 990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (loglevel > LLV_DEBUG) 1000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang RSA_print_fp(stdout, key->rsa, 4); 1010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return NULL; 1030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangvoid 1060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_key_dump(struct genlist *list) 1070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 1080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang genlist_foreach(list, rsa_key_dump_one, NULL); 1090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstatic void * 1120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_list_count_one(void *entry, void *arg) 1130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 1140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (arg) 1150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang (*(unsigned long *)arg)++; 1160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return NULL; 1170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangunsigned long 1200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_list_count(struct genlist *list) 1210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 1220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang unsigned long count = 0; 1230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang genlist_foreach(list, rsa_list_count_one, &count); 1240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return count; 1250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstruct lookup_result { 1280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct ph1handle *iph1; 1290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang int max_score; 1300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct genlist *winners; 1310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}; 1320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstatic void * 1340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_lookup_key_one(void *entry, void *data) 1350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 1360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang int local_score, remote_score; 1370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct lookup_result *req = data; 1380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct rsa_key *key = entry; 1390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang local_score = naddr_score(key->src, req->iph1->local); 1410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang remote_score = naddr_score(key->dst, req->iph1->remote); 1420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang plog(LLV_DEBUG, LOCATION, NULL, "Entry %s scored %d/%d\n", 1440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang naddrwop2str_fromto("%s -> %s", key->src, key->dst), 1450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang local_score, remote_score); 1460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (local_score >= 0 && remote_score >= 0) { 1480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (local_score + remote_score > req->max_score) { 1490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang req->max_score = local_score + remote_score; 1500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang// genlist_free(req->winners, NULL); 1510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 1520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (local_score + remote_score >= req->max_score) { 1540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang genlist_append(req->winners, key); 1550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 1560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 1570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang /* Always traverse the whole list */ 1590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return NULL; 1600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstruct genlist * 1630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_lookup_keys(struct ph1handle *iph1, int my) 1640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 1650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct genlist *list; 1660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct lookup_result r; 1670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang plog(LLV_DEBUG, LOCATION, NULL, "Looking up RSA key for %s\n", 1690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote)); 1700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang r.iph1 = iph1; 1720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang r.max_score = -1; 1730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang r.winners = genlist_init(); 1740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (my) 1760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang list = iph1->rmconf->rsa_private; 1770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang else 1780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang list = iph1->rmconf->rsa_public; 1790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang genlist_foreach(list, rsa_lookup_key_one, &r); 1810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (loglevel >= LLV_DEBUG) 1830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang rsa_key_dump(r.winners); 1840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return r.winners; 1860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint 1890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_parse_file(struct genlist *list, const char *fname, enum rsa_key_type type) 1900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 1910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang int ret; 1920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang plog(LLV_DEBUG, LOCATION, NULL, "Parsing %s\n", fname); 1940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang ret = prsa_parse_file(list, fname, type); 1950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (loglevel >= LLV_DEBUG) 1960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang rsa_key_dump(list); 1970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return ret; 1980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 2000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih WangRSA * 2010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrsa_try_check_rsasign(vchar_t *source, vchar_t *sig, struct genlist *list) 2020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 2030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct rsa_key *key; 2040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct genlist_entry *gp; 2050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 2060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang for(key = genlist_next(list, &gp); key; key = genlist_next(NULL, &gp)) { 2070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang plog(LLV_DEBUG, LOCATION, NULL, "Checking key %s...\n", 2080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang naddrwop2str_fromto("%s -> %s", key->src, key->dst)); 2090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (eay_check_rsasign(source, sig, key->rsa) == 0) { 2100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang plog(LLV_DEBUG, LOCATION, NULL, " ... YEAH!\n"); 2110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return key->rsa; 2120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 2130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang plog(LLV_DEBUG, LOCATION, NULL, " ... nope.\n"); 2140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 2150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return NULL; 2160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 217