LCOV - code coverage report
Current view: top level - src/eap_peer - eap_fast_pac.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 391 513 76.2 %
Date: 2015-09-27 Functions: 26 26 100.0 %

          Line data    Source code
       1             : /*
       2             :  * EAP peer method: EAP-FAST PAC file processing
       3             :  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "eap_config.h"
      13             : #include "eap_i.h"
      14             : #include "eap_fast_pac.h"
      15             : 
      16             : /* TODO: encrypt PAC-Key in the PAC file */
      17             : 
      18             : 
      19             : /* Text data format */
      20             : static const char *pac_file_hdr =
      21             :         "wpa_supplicant EAP-FAST PAC file - version 1";
      22             : 
      23             : /*
      24             :  * Binary data format
      25             :  * 4-octet magic value: 6A E4 92 0C
      26             :  * 2-octet version (big endian)
      27             :  * <version specific data>
      28             :  *
      29             :  * version=0:
      30             :  * Sequence of PAC entries:
      31             :  *   2-octet PAC-Type (big endian)
      32             :  *   32-octet PAC-Key
      33             :  *   2-octet PAC-Opaque length (big endian)
      34             :  *   <variable len> PAC-Opaque data (length bytes)
      35             :  *   2-octet PAC-Info length (big endian)
      36             :  *   <variable len> PAC-Info data (length bytes)
      37             :  */
      38             : 
      39             : #define EAP_FAST_PAC_BINARY_MAGIC 0x6ae4920c
      40             : #define EAP_FAST_PAC_BINARY_FORMAT_VERSION 0
      41             : 
      42             : 
      43             : /**
      44             :  * eap_fast_free_pac - Free PAC data
      45             :  * @pac: Pointer to the PAC entry
      46             :  *
      47             :  * Note that the PAC entry must not be in a list since this function does not
      48             :  * remove the list links.
      49             :  */
      50          23 : void eap_fast_free_pac(struct eap_fast_pac *pac)
      51             : {
      52          23 :         os_free(pac->pac_opaque);
      53          23 :         os_free(pac->pac_info);
      54          23 :         os_free(pac->a_id);
      55          23 :         os_free(pac->i_id);
      56          23 :         os_free(pac->a_id_info);
      57          23 :         os_free(pac);
      58          23 : }
      59             : 
      60             : 
      61             : /**
      62             :  * eap_fast_get_pac - Get a PAC entry based on A-ID
      63             :  * @pac_root: Pointer to root of the PAC list
      64             :  * @a_id: A-ID to search for
      65             :  * @a_id_len: Length of A-ID
      66             :  * @pac_type: PAC-Type to search for
      67             :  * Returns: Pointer to the PAC entry, or %NULL if A-ID not found
      68             :  */
      69          37 : struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
      70             :                                        const u8 *a_id, size_t a_id_len,
      71             :                                        u16 pac_type)
      72             : {
      73          37 :         struct eap_fast_pac *pac = pac_root;
      74             : 
      75          74 :         while (pac) {
      76          22 :                 if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
      77          11 :                     os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
      78          11 :                         return pac;
      79             :                 }
      80           0 :                 pac = pac->next;
      81             :         }
      82          26 :         return NULL;
      83             : }
      84             : 
      85             : 
      86          12 : static void eap_fast_remove_pac(struct eap_fast_pac **pac_root,
      87             :                                 struct eap_fast_pac **pac_current,
      88             :                                 const u8 *a_id, size_t a_id_len, u16 pac_type)
      89             : {
      90             :         struct eap_fast_pac *pac, *prev;
      91             : 
      92          12 :         pac = *pac_root;
      93          12 :         prev = NULL;
      94             : 
      95          24 :         while (pac) {
      96           0 :                 if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
      97           0 :                     os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
      98           0 :                         if (prev == NULL)
      99           0 :                                 *pac_root = pac->next;
     100             :                         else
     101           0 :                                 prev->next = pac->next;
     102           0 :                         if (*pac_current == pac)
     103           0 :                                 *pac_current = NULL;
     104           0 :                         eap_fast_free_pac(pac);
     105           0 :                         break;
     106             :                 }
     107           0 :                 prev = pac;
     108           0 :                 pac = pac->next;
     109             :         }
     110          12 : }
     111             : 
     112             : 
     113          60 : static int eap_fast_copy_buf(u8 **dst, size_t *dst_len,
     114             :                              const u8 *src, size_t src_len)
     115             : {
     116          60 :         if (src) {
     117          60 :                 *dst = os_malloc(src_len);
     118          60 :                 if (*dst == NULL)
     119           0 :                         return -1;
     120          60 :                 os_memcpy(*dst, src, src_len);
     121          60 :                 *dst_len = src_len;
     122             :         }
     123          60 :         return 0;
     124             : }
     125             : 
     126             : 
     127             : /**
     128             :  * eap_fast_add_pac - Add a copy of a PAC entry to a list
     129             :  * @pac_root: Pointer to PAC list root pointer
     130             :  * @pac_current: Pointer to the current PAC pointer
     131             :  * @entry: New entry to clone and add to the list
     132             :  * Returns: 0 on success, -1 on failure
     133             :  *
     134             :  * This function makes a clone of the given PAC entry and adds this copied
     135             :  * entry to the list (pac_root). If an old entry for the same A-ID is found,
     136             :  * it will be removed from the PAC list and in this case, pac_current entry
     137             :  * is set to %NULL if it was the removed entry.
     138             :  */
     139          12 : int eap_fast_add_pac(struct eap_fast_pac **pac_root,
     140             :                      struct eap_fast_pac **pac_current,
     141             :                      struct eap_fast_pac *entry)
     142             : {
     143             :         struct eap_fast_pac *pac;
     144             : 
     145          12 :         if (entry == NULL || entry->a_id == NULL)
     146           0 :                 return -1;
     147             : 
     148             :         /* Remove a possible old entry for the matching A-ID. */
     149          24 :         eap_fast_remove_pac(pac_root, pac_current,
     150          24 :                             entry->a_id, entry->a_id_len, entry->pac_type);
     151             : 
     152             :         /* Allocate a new entry and add it to the list of PACs. */
     153          12 :         pac = os_zalloc(sizeof(*pac));
     154          12 :         if (pac == NULL)
     155           0 :                 return -1;
     156             : 
     157          12 :         pac->pac_type = entry->pac_type;
     158          12 :         os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
     159          24 :         if (eap_fast_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
     160          24 :                               entry->pac_opaque, entry->pac_opaque_len) < 0 ||
     161          24 :             eap_fast_copy_buf(&pac->pac_info, &pac->pac_info_len,
     162          24 :                               entry->pac_info, entry->pac_info_len) < 0 ||
     163          24 :             eap_fast_copy_buf(&pac->a_id, &pac->a_id_len,
     164          24 :                               entry->a_id, entry->a_id_len) < 0 ||
     165          24 :             eap_fast_copy_buf(&pac->i_id, &pac->i_id_len,
     166          24 :                               entry->i_id, entry->i_id_len) < 0 ||
     167          24 :             eap_fast_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
     168          12 :                               entry->a_id_info, entry->a_id_info_len) < 0) {
     169           0 :                 eap_fast_free_pac(pac);
     170           0 :                 return -1;
     171             :         }
     172             : 
     173          12 :         pac->next = *pac_root;
     174          12 :         *pac_root = pac;
     175             : 
     176          12 :         return 0;
     177             : }
     178             : 
     179             : 
     180             : struct eap_fast_read_ctx {
     181             :         FILE *f;
     182             :         const char *pos;
     183             :         const char *end;
     184             :         int line;
     185             :         char *buf;
     186             :         size_t buf_len;
     187             : };
     188             : 
     189          91 : static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char **value)
     190             : {
     191             :         char *pos;
     192             : 
     193          91 :         rc->line++;
     194          91 :         if (rc->f) {
     195          26 :                 if (fgets(rc->buf, rc->buf_len, rc->f) == NULL)
     196           2 :                         return -1;
     197             :         } else {
     198             :                 const char *l_end;
     199             :                 size_t len;
     200          65 :                 if (rc->pos >= rc->end)
     201           5 :                         return -1;
     202          60 :                 l_end = rc->pos;
     203        2604 :                 while (l_end < rc->end && *l_end != '\n')
     204        2484 :                         l_end++;
     205          60 :                 len = l_end - rc->pos;
     206          60 :                 if (len >= rc->buf_len)
     207           0 :                         len = rc->buf_len - 1;
     208          60 :                 os_memcpy(rc->buf, rc->pos, len);
     209          60 :                 rc->buf[len] = '\0';
     210          60 :                 rc->pos = l_end + 1;
     211             :         }
     212             : 
     213          84 :         rc->buf[rc->buf_len - 1] = '\0';
     214          84 :         pos = rc->buf;
     215        3652 :         while (*pos != '\0') {
     216        3508 :                 if (*pos == '\n' || *pos == '\r') {
     217          24 :                         *pos = '\0';
     218          24 :                         break;
     219             :                 }
     220        3484 :                 pos++;
     221             :         }
     222             : 
     223          84 :         pos = os_strchr(rc->buf, '=');
     224          84 :         if (pos)
     225          63 :                 *pos++ = '\0';
     226          84 :         *value = pos;
     227             : 
     228          84 :         return 0;
     229             : }
     230             : 
     231             : 
     232          35 : static u8 * eap_fast_parse_hex(const char *value, size_t *len)
     233             : {
     234             :         int hlen;
     235             :         u8 *buf;
     236             : 
     237          35 :         if (value == NULL)
     238           0 :                 return NULL;
     239          35 :         hlen = os_strlen(value);
     240          35 :         if (hlen & 1)
     241           0 :                 return NULL;
     242          35 :         *len = hlen / 2;
     243          35 :         buf = os_malloc(*len);
     244          35 :         if (buf == NULL)
     245           0 :                 return NULL;
     246          35 :         if (hexstr2bin(value, buf, *len)) {
     247           0 :                 os_free(buf);
     248           0 :                 return NULL;
     249             :         }
     250          35 :         return buf;
     251             : }
     252             : 
     253             : 
     254          19 : static int eap_fast_init_pac_data(struct eap_sm *sm, const char *pac_file,
     255             :                                   struct eap_fast_read_ctx *rc)
     256             : {
     257          19 :         os_memset(rc, 0, sizeof(*rc));
     258             : 
     259          19 :         rc->buf_len = 2048;
     260          19 :         rc->buf = os_malloc(rc->buf_len);
     261          19 :         if (rc->buf == NULL)
     262           0 :                 return -1;
     263             : 
     264          19 :         if (os_strncmp(pac_file, "blob://", 7) == 0) {
     265             :                 const struct wpa_config_blob *blob;
     266          16 :                 blob = eap_get_config_blob(sm, pac_file + 7);
     267          16 :                 if (blob == NULL) {
     268          11 :                         wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
     269             :                                    "assume no PAC entries have been "
     270             :                                    "provisioned", pac_file + 7);
     271          11 :                         os_free(rc->buf);
     272          11 :                         return -1;
     273             :                 }
     274           5 :                 rc->pos = (char *) blob->data;
     275           5 :                 rc->end = (char *) blob->data + blob->len;
     276             :         } else {
     277           3 :                 rc->f = fopen(pac_file, "rb");
     278           3 :                 if (rc->f == NULL) {
     279           1 :                         wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
     280             :                                    "assume no PAC entries have been "
     281             :                                    "provisioned", pac_file);
     282           1 :                         os_free(rc->buf);
     283           1 :                         return -1;
     284             :                 }
     285             :         }
     286             : 
     287           7 :         return 0;
     288             : }
     289             : 
     290             : 
     291           7 : static void eap_fast_deinit_pac_data(struct eap_fast_read_ctx *rc)
     292             : {
     293           7 :         os_free(rc->buf);
     294           7 :         if (rc->f)
     295           2 :                 fclose(rc->f);
     296           7 : }
     297             : 
     298             : 
     299           7 : static const char * eap_fast_parse_start(struct eap_fast_pac **pac)
     300             : {
     301           7 :         if (*pac)
     302           0 :                 return "START line without END";
     303             : 
     304           7 :         *pac = os_zalloc(sizeof(struct eap_fast_pac));
     305           7 :         if (*pac == NULL)
     306           0 :                 return "No memory for PAC entry";
     307           7 :         (*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
     308           7 :         return NULL;
     309             : }
     310             : 
     311             : 
     312           7 : static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root,
     313             :                                        struct eap_fast_pac **pac)
     314             : {
     315           7 :         if (*pac == NULL)
     316           0 :                 return "END line without START";
     317           7 :         if (*pac_root) {
     318           0 :                 struct eap_fast_pac *end = *pac_root;
     319           0 :                 while (end->next)
     320           0 :                         end = end->next;
     321           0 :                 end->next = *pac;
     322             :         } else
     323           7 :                 *pac_root = *pac;
     324             : 
     325           7 :         *pac = NULL;
     326           7 :         return NULL;
     327             : }
     328             : 
     329             : 
     330           7 : static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac,
     331             :                                             char *pos)
     332             : {
     333           7 :         if (!pos)
     334           0 :                 return "Cannot parse pac type";
     335           7 :         pac->pac_type = atoi(pos);
     336           7 :         if (pac->pac_type != PAC_TYPE_TUNNEL_PAC &&
     337           0 :             pac->pac_type != PAC_TYPE_USER_AUTHORIZATION &&
     338           0 :             pac->pac_type != PAC_TYPE_MACHINE_AUTHENTICATION)
     339           0 :                 return "Unrecognized PAC-Type";
     340             : 
     341           7 :         return NULL;
     342             : }
     343             : 
     344             : 
     345           7 : static const char * eap_fast_parse_pac_key(struct eap_fast_pac *pac, char *pos)
     346             : {
     347             :         u8 *key;
     348             :         size_t key_len;
     349             : 
     350           7 :         key = eap_fast_parse_hex(pos, &key_len);
     351           7 :         if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
     352           0 :                 os_free(key);
     353           0 :                 return "Invalid PAC-Key";
     354             :         }
     355             : 
     356           7 :         os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
     357           7 :         os_free(key);
     358             : 
     359           7 :         return NULL;
     360             : }
     361             : 
     362             : 
     363           7 : static const char * eap_fast_parse_pac_opaque(struct eap_fast_pac *pac,
     364             :                                               char *pos)
     365             : {
     366           7 :         os_free(pac->pac_opaque);
     367           7 :         pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len);
     368           7 :         if (pac->pac_opaque == NULL)
     369           0 :                 return "Invalid PAC-Opaque";
     370           7 :         return NULL;
     371             : }
     372             : 
     373             : 
     374           7 : static const char * eap_fast_parse_a_id(struct eap_fast_pac *pac, char *pos)
     375             : {
     376           7 :         os_free(pac->a_id);
     377           7 :         pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
     378           7 :         if (pac->a_id == NULL)
     379           0 :                 return "Invalid A-ID";
     380           7 :         return NULL;
     381             : }
     382             : 
     383             : 
     384           7 : static const char * eap_fast_parse_i_id(struct eap_fast_pac *pac, char *pos)
     385             : {
     386           7 :         os_free(pac->i_id);
     387           7 :         pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
     388           7 :         if (pac->i_id == NULL)
     389           0 :                 return "Invalid I-ID";
     390           7 :         return NULL;
     391             : }
     392             : 
     393             : 
     394           7 : static const char * eap_fast_parse_a_id_info(struct eap_fast_pac *pac,
     395             :                                              char *pos)
     396             : {
     397           7 :         os_free(pac->a_id_info);
     398           7 :         pac->a_id_info = eap_fast_parse_hex(pos, &pac->a_id_info_len);
     399           7 :         if (pac->a_id_info == NULL)
     400           0 :                 return "Invalid A-ID-Info";
     401           7 :         return NULL;
     402             : }
     403             : 
     404             : 
     405             : /**
     406             :  * eap_fast_load_pac - Load PAC entries (text format)
     407             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     408             :  * @pac_root: Pointer to root of the PAC list (to be filled)
     409             :  * @pac_file: Name of the PAC file/blob to load
     410             :  * Returns: 0 on success, -1 on failure
     411             :  */
     412          19 : int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
     413             :                       const char *pac_file)
     414             : {
     415             :         struct eap_fast_read_ctx rc;
     416          19 :         struct eap_fast_pac *pac = NULL;
     417          19 :         int count = 0;
     418             :         char *pos;
     419          19 :         const char *err = NULL;
     420             : 
     421          19 :         if (pac_file == NULL)
     422           0 :                 return -1;
     423             : 
     424          19 :         if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0)
     425          12 :                 return 0;
     426             : 
     427           7 :         if (eap_fast_read_line(&rc, &pos) < 0) {
     428             :                 /* empty file - assume it is fine to overwrite */
     429           0 :                 eap_fast_deinit_pac_data(&rc);
     430           0 :                 return 0;
     431             :         }
     432           7 :         if (os_strcmp(pac_file_hdr, rc.buf) != 0)
     433           0 :                 err = "Unrecognized header line";
     434             : 
     435          91 :         while (!err && eap_fast_read_line(&rc, &pos) == 0) {
     436          77 :                 if (os_strcmp(rc.buf, "START") == 0)
     437           7 :                         err = eap_fast_parse_start(&pac);
     438          70 :                 else if (os_strcmp(rc.buf, "END") == 0) {
     439           7 :                         err = eap_fast_parse_end(pac_root, &pac);
     440           7 :                         count++;
     441          63 :                 } else if (!pac)
     442           0 :                         err = "Unexpected line outside START/END block";
     443          63 :                 else if (os_strcmp(rc.buf, "PAC-Type") == 0)
     444           7 :                         err = eap_fast_parse_pac_type(pac, pos);
     445          56 :                 else if (os_strcmp(rc.buf, "PAC-Key") == 0)
     446           7 :                         err = eap_fast_parse_pac_key(pac, pos);
     447          49 :                 else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
     448           7 :                         err = eap_fast_parse_pac_opaque(pac, pos);
     449          42 :                 else if (os_strcmp(rc.buf, "A-ID") == 0)
     450           7 :                         err = eap_fast_parse_a_id(pac, pos);
     451          35 :                 else if (os_strcmp(rc.buf, "I-ID") == 0)
     452           7 :                         err = eap_fast_parse_i_id(pac, pos);
     453          28 :                 else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
     454           7 :                         err = eap_fast_parse_a_id_info(pac, pos);
     455             :         }
     456             : 
     457           7 :         if (pac) {
     458           0 :                 err = "PAC block not terminated with END";
     459           0 :                 eap_fast_free_pac(pac);
     460             :         }
     461             : 
     462           7 :         eap_fast_deinit_pac_data(&rc);
     463             : 
     464           7 :         if (err) {
     465           0 :                 wpa_printf(MSG_INFO, "EAP-FAST: %s in '%s:%d'",
     466             :                            err, pac_file, rc.line);
     467           0 :                 return -1;
     468             :         }
     469             : 
     470           7 :         wpa_printf(MSG_DEBUG, "EAP-FAST: Read %d PAC entries from '%s'",
     471             :                    count, pac_file);
     472             : 
     473           7 :         return 0;
     474             : }
     475             : 
     476             : 
     477          60 : static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
     478             :                            const char *field, const u8 *data,
     479             :                            size_t len, int txt)
     480             : {
     481             :         size_t i, need;
     482             :         int ret;
     483             :         char *end;
     484             : 
     485          60 :         if (data == NULL || buf == NULL || *buf == NULL ||
     486          60 :             pos == NULL || *pos == NULL || *pos < *buf)
     487           0 :                 return;
     488             : 
     489          60 :         need = os_strlen(field) + len * 2 + 30;
     490          60 :         if (txt)
     491          20 :                 need += os_strlen(field) + len + 20;
     492             : 
     493          60 :         if (*pos - *buf + need > *buf_len) {
     494           0 :                 char *nbuf = os_realloc(*buf, *buf_len + need);
     495           0 :                 if (nbuf == NULL) {
     496           0 :                         os_free(*buf);
     497           0 :                         *buf = NULL;
     498           0 :                         return;
     499             :                 }
     500           0 :                 *pos = nbuf + (*pos - *buf);
     501           0 :                 *buf = nbuf;
     502           0 :                 *buf_len += need;
     503             :         }
     504          60 :         end = *buf + *buf_len;
     505             : 
     506          60 :         ret = os_snprintf(*pos, end - *pos, "%s=", field);
     507          60 :         if (os_snprintf_error(end - *pos, ret))
     508           0 :                 return;
     509          60 :         *pos += ret;
     510          60 :         *pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
     511          60 :         ret = os_snprintf(*pos, end - *pos, "\n");
     512          60 :         if (os_snprintf_error(end - *pos, ret))
     513           0 :                 return;
     514          60 :         *pos += ret;
     515             : 
     516          60 :         if (txt) {
     517          20 :                 ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
     518          20 :                 if (os_snprintf_error(end - *pos, ret))
     519           0 :                         return;
     520          20 :                 *pos += ret;
     521         212 :                 for (i = 0; i < len; i++) {
     522         192 :                         ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
     523         192 :                         if (os_snprintf_error(end - *pos, ret))
     524           0 :                                 return;
     525         192 :                         *pos += ret;
     526             :                 }
     527          20 :                 ret = os_snprintf(*pos, end - *pos, "\n");
     528          20 :                 if (os_snprintf_error(end - *pos, ret))
     529           0 :                         return;
     530          20 :                 *pos += ret;
     531             :         }
     532             : }
     533             : 
     534             : 
     535          12 : static int eap_fast_write_pac(struct eap_sm *sm, const char *pac_file,
     536             :                               char *buf, size_t len)
     537             : {
     538          12 :         if (os_strncmp(pac_file, "blob://", 7) == 0) {
     539             :                 struct wpa_config_blob *blob;
     540          10 :                 blob = os_zalloc(sizeof(*blob));
     541          10 :                 if (blob == NULL)
     542           0 :                         return -1;
     543          10 :                 blob->data = (u8 *) buf;
     544          10 :                 blob->len = len;
     545          10 :                 buf = NULL;
     546          10 :                 blob->name = os_strdup(pac_file + 7);
     547          10 :                 if (blob->name == NULL) {
     548           0 :                         os_free(blob);
     549           0 :                         return -1;
     550             :                 }
     551          10 :                 eap_set_config_blob(sm, blob);
     552             :         } else {
     553             :                 FILE *f;
     554           2 :                 f = fopen(pac_file, "wb");
     555           2 :                 if (f == NULL) {
     556           0 :                         wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
     557             :                                    "file '%s' for writing", pac_file);
     558           0 :                         return -1;
     559             :                 }
     560           2 :                 if (fwrite(buf, 1, len, f) != len) {
     561           0 :                         wpa_printf(MSG_INFO, "EAP-FAST: Failed to write all "
     562             :                                    "PACs into '%s'", pac_file);
     563           0 :                         fclose(f);
     564           0 :                         return -1;
     565             :                 }
     566           2 :                 os_free(buf);
     567           2 :                 fclose(f);
     568             :         }
     569             : 
     570          12 :         return 0;
     571             : }
     572             : 
     573             : 
     574          10 : static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf,
     575             :                                  char **pos, size_t *buf_len)
     576             : {
     577             :         int ret;
     578             : 
     579          10 :         ret = os_snprintf(*pos, *buf + *buf_len - *pos,
     580          10 :                           "START\nPAC-Type=%d\n", pac->pac_type);
     581          10 :         if (os_snprintf_error(*buf + *buf_len - *pos, ret))
     582           0 :                 return -1;
     583             : 
     584          10 :         *pos += ret;
     585          10 :         eap_fast_write(buf, pos, buf_len, "PAC-Key",
     586          10 :                        pac->pac_key, EAP_FAST_PAC_KEY_LEN, 0);
     587          20 :         eap_fast_write(buf, pos, buf_len, "PAC-Opaque",
     588          10 :                        pac->pac_opaque, pac->pac_opaque_len, 0);
     589          20 :         eap_fast_write(buf, pos, buf_len, "PAC-Info",
     590          10 :                        pac->pac_info, pac->pac_info_len, 0);
     591          20 :         eap_fast_write(buf, pos, buf_len, "A-ID",
     592          10 :                        pac->a_id, pac->a_id_len, 0);
     593          20 :         eap_fast_write(buf, pos, buf_len, "I-ID",
     594          10 :                        pac->i_id, pac->i_id_len, 1);
     595          20 :         eap_fast_write(buf, pos, buf_len, "A-ID-Info",
     596          10 :                        pac->a_id_info, pac->a_id_info_len, 1);
     597          10 :         if (*buf == NULL) {
     598           0 :                 wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
     599             :                            "data");
     600           0 :                 return -1;
     601             :         }
     602          10 :         ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
     603          10 :         if (os_snprintf_error(*buf + *buf_len - *pos, ret))
     604           0 :                 return -1;
     605          10 :         *pos += ret;
     606             : 
     607          10 :         return 0;
     608             : }
     609             : 
     610             : 
     611             : /**
     612             :  * eap_fast_save_pac - Save PAC entries (text format)
     613             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     614             :  * @pac_root: Root of the PAC list
     615             :  * @pac_file: Name of the PAC file/blob
     616             :  * Returns: 0 on success, -1 on failure
     617             :  */
     618          10 : int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
     619             :                       const char *pac_file)
     620             : {
     621             :         struct eap_fast_pac *pac;
     622          10 :         int ret, count = 0;
     623             :         char *buf, *pos;
     624             :         size_t buf_len;
     625             : 
     626          10 :         if (pac_file == NULL)
     627           0 :                 return -1;
     628             : 
     629          10 :         buf_len = 1024;
     630          10 :         pos = buf = os_malloc(buf_len);
     631          10 :         if (buf == NULL)
     632           0 :                 return -1;
     633             : 
     634          10 :         ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
     635          10 :         if (os_snprintf_error(buf + buf_len - pos, ret)) {
     636           0 :                 os_free(buf);
     637           0 :                 return -1;
     638             :         }
     639          10 :         pos += ret;
     640             : 
     641          10 :         pac = pac_root;
     642          30 :         while (pac) {
     643          10 :                 if (eap_fast_add_pac_data(pac, &buf, &pos, &buf_len)) {
     644           0 :                         os_free(buf);
     645           0 :                         return -1;
     646             :                 }
     647          10 :                 count++;
     648          10 :                 pac = pac->next;
     649             :         }
     650             : 
     651          10 :         if (eap_fast_write_pac(sm, pac_file, buf, pos - buf)) {
     652           0 :                 os_free(buf);
     653           0 :                 return -1;
     654             :         }
     655             : 
     656          10 :         wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %d PAC entries into '%s'",
     657             :                    count, pac_file);
     658             : 
     659          10 :         return 0;
     660             : }
     661             : 
     662             : 
     663             : /**
     664             :  * eap_fast_pac_list_truncate - Truncate a PAC list to the given length
     665             :  * @pac_root: Root of the PAC list
     666             :  * @max_len: Maximum length of the list (>= 1)
     667             :  * Returns: Number of PAC entries removed
     668             :  */
     669          37 : size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
     670             :                                   size_t max_len)
     671             : {
     672             :         struct eap_fast_pac *pac, *prev;
     673             :         size_t count;
     674             : 
     675          37 :         pac = pac_root;
     676          37 :         prev = NULL;
     677          37 :         count = 0;
     678             : 
     679          97 :         while (pac) {
     680          23 :                 count++;
     681          23 :                 if (count > max_len)
     682           0 :                         break;
     683          23 :                 prev = pac;
     684          23 :                 pac = pac->next;
     685             :         }
     686             : 
     687          37 :         if (count <= max_len || prev == NULL)
     688          37 :                 return 0;
     689             : 
     690           0 :         count = 0;
     691           0 :         prev->next = NULL;
     692             : 
     693           0 :         while (pac) {
     694           0 :                 prev = pac;
     695           0 :                 pac = pac->next;
     696           0 :                 eap_fast_free_pac(prev);
     697           0 :                 count++;
     698             :         }
     699             : 
     700           0 :         return count;
     701             : }
     702             : 
     703             : 
     704           4 : static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
     705             : {
     706             :         u8 *pos, *end;
     707             :         u16 type, len;
     708             : 
     709           4 :         pos = pac->pac_info;
     710           4 :         end = pos + pac->pac_info_len;
     711             : 
     712          28 :         while (pos + 4 < end) {
     713          20 :                 type = WPA_GET_BE16(pos);
     714          20 :                 pos += 2;
     715          20 :                 len = WPA_GET_BE16(pos);
     716          20 :                 pos += 2;
     717          20 :                 if (len > (unsigned int) (end - pos))
     718           0 :                         break;
     719             : 
     720          20 :                 if (type == PAC_TYPE_A_ID) {
     721           4 :                         os_free(pac->a_id);
     722           4 :                         pac->a_id = os_malloc(len);
     723           4 :                         if (pac->a_id == NULL)
     724           0 :                                 break;
     725           4 :                         os_memcpy(pac->a_id, pos, len);
     726           4 :                         pac->a_id_len = len;
     727             :                 }
     728             : 
     729          20 :                 if (type == PAC_TYPE_A_ID_INFO) {
     730           4 :                         os_free(pac->a_id_info);
     731           4 :                         pac->a_id_info = os_malloc(len);
     732           4 :                         if (pac->a_id_info == NULL)
     733           0 :                                 break;
     734           4 :                         os_memcpy(pac->a_id_info, pos, len);
     735           4 :                         pac->a_id_info_len = len;
     736             :                 }
     737             : 
     738          20 :                 pos += len;
     739             :         }
     740           4 : }
     741             : 
     742             : 
     743             : /**
     744             :  * eap_fast_load_pac_bin - Load PAC entries (binary format)
     745             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     746             :  * @pac_root: Pointer to root of the PAC list (to be filled)
     747             :  * @pac_file: Name of the PAC file/blob to load
     748             :  * Returns: 0 on success, -1 on failure
     749             :  */
     750           6 : int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
     751             :                           const char *pac_file)
     752             : {
     753           6 :         const struct wpa_config_blob *blob = NULL;
     754             :         u8 *buf, *end, *pos;
     755           6 :         size_t len, count = 0;
     756             :         struct eap_fast_pac *pac, *prev;
     757             : 
     758           6 :         *pac_root = NULL;
     759             : 
     760           6 :         if (pac_file == NULL)
     761           0 :                 return -1;
     762             : 
     763           6 :         if (os_strncmp(pac_file, "blob://", 7) == 0) {
     764           3 :                 blob = eap_get_config_blob(sm, pac_file + 7);
     765           3 :                 if (blob == NULL) {
     766           1 :                         wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
     767             :                                    "assume no PAC entries have been "
     768             :                                    "provisioned", pac_file + 7);
     769           1 :                         return 0;
     770             :                 }
     771           2 :                 buf = blob->data;
     772           2 :                 len = blob->len;
     773             :         } else {
     774           3 :                 buf = (u8 *) os_readfile(pac_file, &len);
     775           3 :                 if (buf == NULL) {
     776           1 :                         wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
     777             :                                    "assume no PAC entries have been "
     778             :                                    "provisioned", pac_file);
     779           1 :                         return 0;
     780             :                 }
     781             :         }
     782             : 
     783           4 :         if (len == 0) {
     784           0 :                 if (blob == NULL)
     785           0 :                         os_free(buf);
     786           0 :                 return 0;
     787             :         }
     788             : 
     789           8 :         if (len < 6 || WPA_GET_BE32(buf) != EAP_FAST_PAC_BINARY_MAGIC ||
     790           4 :             WPA_GET_BE16(buf + 4) != EAP_FAST_PAC_BINARY_FORMAT_VERSION) {
     791           0 :                 wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC file '%s' (bin)",
     792             :                            pac_file);
     793           0 :                 if (blob == NULL)
     794           0 :                         os_free(buf);
     795           0 :                 return -1;
     796             :         }
     797             : 
     798           4 :         pac = prev = NULL;
     799           4 :         pos = buf + 6;
     800           4 :         end = buf + len;
     801          12 :         while (pos < end) {
     802             :                 u16 val;
     803             : 
     804           4 :                 if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2)
     805           0 :                         goto parse_fail;
     806             : 
     807           4 :                 pac = os_zalloc(sizeof(*pac));
     808           4 :                 if (pac == NULL)
     809           0 :                         goto parse_fail;
     810             : 
     811           4 :                 pac->pac_type = WPA_GET_BE16(pos);
     812           4 :                 pos += 2;
     813           4 :                 os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
     814           4 :                 pos += EAP_FAST_PAC_KEY_LEN;
     815           4 :                 val = WPA_GET_BE16(pos);
     816           4 :                 pos += 2;
     817           4 :                 if (val > end - pos)
     818           0 :                         goto parse_fail;
     819           4 :                 pac->pac_opaque_len = val;
     820           4 :                 pac->pac_opaque = os_malloc(pac->pac_opaque_len);
     821           4 :                 if (pac->pac_opaque == NULL)
     822           0 :                         goto parse_fail;
     823           4 :                 os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
     824           4 :                 pos += pac->pac_opaque_len;
     825           4 :                 if (2 > end - pos)
     826           0 :                         goto parse_fail;
     827           4 :                 val = WPA_GET_BE16(pos);
     828           4 :                 pos += 2;
     829           4 :                 if (val > end - pos)
     830           0 :                         goto parse_fail;
     831           4 :                 pac->pac_info_len = val;
     832           4 :                 pac->pac_info = os_malloc(pac->pac_info_len);
     833           4 :                 if (pac->pac_info == NULL)
     834           0 :                         goto parse_fail;
     835           4 :                 os_memcpy(pac->pac_info, pos, pac->pac_info_len);
     836           4 :                 pos += pac->pac_info_len;
     837           4 :                 eap_fast_pac_get_a_id(pac);
     838             : 
     839           4 :                 count++;
     840           4 :                 if (prev)
     841           0 :                         prev->next = pac;
     842             :                 else
     843           4 :                         *pac_root = pac;
     844           4 :                 prev = pac;
     845             :         }
     846             : 
     847           4 :         if (blob == NULL)
     848           2 :                 os_free(buf);
     849             : 
     850           4 :         wpa_printf(MSG_DEBUG, "EAP-FAST: Read %lu PAC entries from '%s' (bin)",
     851             :                    (unsigned long) count, pac_file);
     852             : 
     853           4 :         return 0;
     854             : 
     855             : parse_fail:
     856           0 :         wpa_printf(MSG_INFO, "EAP-FAST: Failed to parse PAC file '%s' (bin)",
     857             :                    pac_file);
     858           0 :         if (blob == NULL)
     859           0 :                 os_free(buf);
     860           0 :         if (pac)
     861           0 :                 eap_fast_free_pac(pac);
     862           0 :         return -1;
     863             : }
     864             : 
     865             : 
     866             : /**
     867             :  * eap_fast_save_pac_bin - Save PAC entries (binary format)
     868             :  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
     869             :  * @pac_root: Root of the PAC list
     870             :  * @pac_file: Name of the PAC file/blob
     871             :  * Returns: 0 on success, -1 on failure
     872             :  */
     873           2 : int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
     874             :                           const char *pac_file)
     875             : {
     876           2 :         size_t len, count = 0;
     877             :         struct eap_fast_pac *pac;
     878             :         u8 *buf, *pos;
     879             : 
     880           2 :         len = 6;
     881           2 :         pac = pac_root;
     882           6 :         while (pac) {
     883           4 :                 if (pac->pac_opaque_len > 65535 ||
     884           2 :                     pac->pac_info_len > 65535)
     885           0 :                         return -1;
     886           4 :                 len += 2 + EAP_FAST_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
     887           2 :                         2 + pac->pac_info_len;
     888           2 :                 pac = pac->next;
     889             :         }
     890             : 
     891           2 :         buf = os_malloc(len);
     892           2 :         if (buf == NULL)
     893           0 :                 return -1;
     894             : 
     895           2 :         pos = buf;
     896           2 :         WPA_PUT_BE32(pos, EAP_FAST_PAC_BINARY_MAGIC);
     897           2 :         pos += 4;
     898           2 :         WPA_PUT_BE16(pos, EAP_FAST_PAC_BINARY_FORMAT_VERSION);
     899           2 :         pos += 2;
     900             : 
     901           2 :         pac = pac_root;
     902           6 :         while (pac) {
     903           2 :                 WPA_PUT_BE16(pos, pac->pac_type);
     904           2 :                 pos += 2;
     905           2 :                 os_memcpy(pos, pac->pac_key, EAP_FAST_PAC_KEY_LEN);
     906           2 :                 pos += EAP_FAST_PAC_KEY_LEN;
     907           2 :                 WPA_PUT_BE16(pos, pac->pac_opaque_len);
     908           2 :                 pos += 2;
     909           2 :                 os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
     910           2 :                 pos += pac->pac_opaque_len;
     911           2 :                 WPA_PUT_BE16(pos, pac->pac_info_len);
     912           2 :                 pos += 2;
     913           2 :                 os_memcpy(pos, pac->pac_info, pac->pac_info_len);
     914           2 :                 pos += pac->pac_info_len;
     915             : 
     916           2 :                 pac = pac->next;
     917           2 :                 count++;
     918             :         }
     919             : 
     920           2 :         if (eap_fast_write_pac(sm, pac_file, (char *) buf, len)) {
     921           0 :                 os_free(buf);
     922           0 :                 return -1;
     923             :         }
     924             : 
     925           2 :         wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %lu PAC entries into '%s' "
     926             :                    "(bin)", (unsigned long) count, pac_file);
     927             : 
     928           2 :         return 0;
     929             : }

Generated by: LCOV version 1.10