示例#1
0
文件: pngset.c 项目: 15521054523/fis3
void PNGAPI
png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
    int chunk, int location)
{
   /* This API is pretty pointless in 1.6.0 because the location can be set
    * before the call to png_set_unknown_chunks.
    *
    * TODO: add a png_app_warning in 1.7
    */
   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
      chunk < info_ptr->unknown_chunks_num)
   {
      if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
      {
         png_app_error(png_ptr, "invalid unknown chunk location");
         /* Fake out the pre 1.6.0 behavior: */
         if ((location & PNG_HAVE_IDAT) != 0) /* undocumented! */
            location = PNG_AFTER_IDAT;

         else
            location = PNG_HAVE_IHDR; /* also undocumented */
      }

      info_ptr->unknown_chunks[chunk].location =
         check_location(png_ptr, location);
   }
}
示例#2
0
void update_all(node **head, int step, date_time time_stamp) {
    node *current = *head;
    for (current = *head; current != NULL; current = current->next) {

        current->loc = update_location(current->loc, current->speed,
                current->course, step);

        int new_area = check_location(current->loc, current->course);
        FILE *log = fopen(log_file, "a");
        if (current->in_area == 0 && new_area != 0) {
            printf("\nShip %s has left shipping area", current->ais_id);

            fprintf(log, "\nShip left: %s\nTime: %d %d %d %d:%d:%d",
                    current->ais_id,
                    time_stamp.day, time_stamp.month, time_stamp.year,
                    time_stamp.hours, time_stamp.minutes, time_stamp.seconds);

        } else if (current->in_area != 0 && new_area == 0) {
            printf("\nShip %s has entered shipping area", current->ais_id);

            fprintf(log, "Ship Entered: %s\nTime: %d %d %d %d:%d:%d",
                    current->ais_id,
                    time_stamp.day, time_stamp.month, time_stamp.year,
                    time_stamp.hours, time_stamp.minutes, time_stamp.seconds);
        }
        fclose(log);
        current->in_area = new_area;
    }
}
示例#3
0
/* 
 * Format: 
 * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
 * the '.' may be an abbrevation
 */
static void check_location_string(struct seq_file *m, const char *c)
{
	while (*c) {
		if (isalpha(*c) || *c == '.')
			check_location(m, c);
		else if (*c == '/' || *c == '-')
			seq_printf(m, " at ");
		c++;
	}
}
示例#4
0
/*
 * Rewind the buffer, and check that the virtual pointer is at 0.
 * buffer:	the buffer to rewind
 * returns	1 if the rewind was successful, 0 otherwise
 */
static int check_rewind(file_buffer_t *buffer)
{
	rewind_buffer(buffer);

	if (!check_location(buffer, 0)) {
		printlg(ERROR_LEVEL, "Failed to rewind.\n");
		return 0;
	}

	return 1;
}
/*****************************************************************
 checks to see if passed token has a valid move
 
 Parameters:
    char: either 'B' or 'W', token of player to check for;
    int: size of the board;
    char**: 2d array of the board;
 
 Returns:
    0: if no moves;
    1: if has valid moves;
 *****************************************************************/
int check_valid_moves(char token, int size, char board[][size]) {
    
    //move through each row
    for (int i = 0; i < size; i++) {
        
        //move through each column
        for (int j = 0; j < size; j++) {
            
            //check if location has been played
            if (board[i][j] == '-') {
                
                /*check if there is a valid move from this location
                 if there is one valid more for this token stop
                 looking and return true*/
                if (check_location(token, i, j, size, board) > 0) {
                    return 1;
                }
            }
        }
    }
    return 0;
}
示例#6
0
/**
 * main function prompts user for input, reads file and runs simulate function.
 */
int main(int argc, char** argv) {
    date_time time_stamp;
    char path[100], ais_id[21];
    double duration, lat, lng, course, speed;
    int mins_duration, step;
    FILE *file;
    node *list_head = NULL;
/*get information from user*/
    printf("Please enter the path of the file of ship data: ");
    scanf(" %s", path);
    printf("Please enter the size of each time step in mins: ");
    scanf("%d", &step);
    printf("Please enter the duration of the simulation in hours(1.5 = 1h 30m): ");
    scanf("%lf", &duration);
    mins_duration = duration * 60; //multiply by 60 to get duration in minutes.
    /*attempt to read file, and simulate if read succeeds*/
    file = fopen(path, "r");
    if (file != NULL) {
        fscanf(file, "%d %d %d %d %d %d", 
                &time_stamp.day, &time_stamp.month, &time_stamp.year,
                &time_stamp.hours, &time_stamp.minutes, &time_stamp.seconds);
        sprintf(log_file, "./LOG_%d_%d_%d_%d_%d_%d", 
                time_stamp.day, time_stamp.month, time_stamp.year,
                time_stamp.hours, time_stamp.minutes, time_stamp.seconds);
        while ((fscanf(file, " %s %lf %lf %lf %lf",
                ais_id, &lat, &lng, &course, &speed)) != EOF) {
            node *new_node = make_node(ais_id, lat, lng, course, speed);
            new_node->in_area = check_location(new_node->loc, new_node->course);
            add_node(&list_head, new_node);
        }
        fclose(file);
        simulate(&list_head, step, mins_duration, &time_stamp);
        print_all(&list_head);
    } else {
        printf("\nfile not found");
    }
    return (EXIT_SUCCESS);
}
示例#7
0
文件: pngset.c 项目: 15521054523/fis3
void PNGAPI
png_set_unknown_chunks(png_const_structrp png_ptr,
   png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
{
   png_unknown_chunkp np;

   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
       unknowns == NULL)
      return;

   /* Check for the failure cases where support has been disabled at compile
    * time.  This code is hardly ever compiled - it's here because
    * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
    * code) but may be meaningless if the read or write handling of unknown
    * chunks is not compiled in.
    */
#  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
      defined(PNG_READ_SUPPORTED)
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
      {
         png_app_error(png_ptr, "no unknown chunk support on read");

         return;
      }
#  endif
#  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
      defined(PNG_WRITE_SUPPORTED)
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
      {
         png_app_error(png_ptr, "no unknown chunk support on write");

         return;
      }
#  endif

   /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that
    * unknown critical chunks could be lost with just a warning resulting in
    * undefined behavior.  Now png_chunk_report is used to provide behavior
    * appropriate to read or write.
    */
   np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,
         info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
         sizeof *np));

   if (np == NULL)
   {
      png_chunk_report(png_ptr, "too many unknown chunks",
         PNG_CHUNK_WRITE_ERROR);

      return;
   }

   png_free(png_ptr, info_ptr->unknown_chunks);
   info_ptr->unknown_chunks = np; /* safe because it is initialized */
   info_ptr->free_me |= PNG_FREE_UNKN;

   np += info_ptr->unknown_chunks_num;

   /* Increment unknown_chunks_num each time round the loop to protect the
    * just-allocated chunk data.
    */
   for (; num_unknowns > 0; --num_unknowns, ++unknowns)
   {
      memcpy(np->name, unknowns->name, (sizeof np->name));
      np->name[(sizeof np->name)-1] = '\0';
      np->location = check_location(png_ptr, unknowns->location);

      if (unknowns->size == 0)
      {
         np->data = NULL;
         np->size = 0;
      }

      else
      {
         np->data = png_voidcast(png_bytep,
            png_malloc_base(png_ptr, unknowns->size));

         if (np->data == NULL)
         {
            png_chunk_report(png_ptr, "unknown chunk: out of memory",
               PNG_CHUNK_WRITE_ERROR);
            /* But just skip storing the unknown chunk */
            continue;
         }

         memcpy(np->data, unknowns->data, unknowns->size);
         np->size = unknowns->size;
      }

      /* These increments are skipped on out-of-memory for the data - the
       * unknown chunk entry gets overwritten if the png_chunk_report returns.
       * This is correct in the read case (the chunk is just dropped.)
       */
      ++np;
      ++(info_ptr->unknown_chunks_num);
   }
}
示例#8
0
/*
 * helper function for automatically finding an invalid seeking mode
 * returns	a seeking mode that is not one of the 3 legal ones
 */
static int find_bad_mode()
{
#ifdef DEBUG
	size_t n_tries = 0;
#endif /* DEBUG */
	int try = INT_MIN;

	while (try <= INT_MAX) {
		if (try != SEEK_SET && try != SEEK_CUR && try != SEEK_END) {
			return try;
		}

		try++;

#ifdef DEBUG
		n_tries++;
		debug_assert(n_tries < N_SEEK_MODES);
#endif /* DEBUG */
	}

	return try;
}

/*
 * Test that an error in "fseek_buffer" is properly caught,
 * and does not change the state of the buffer.
 * buffer:		the buffer in which to make an invalid seek
 * offset:		the "offset" argument to "fseek_buffer"
 * whence:		the "whence" argument to "fseek_buffer"
 * expected_errno:	the expected value of "errno"
 * returns		1 if the error was properly handled, 0 otherwise
 */
static int test_fseek_error(file_buffer_t *buffer, long offset, int whence,
			    int expected_errno)
{
	long old_location = ftell_buffer(buffer);

	if (fseek_buffer(buffer, offset, whence) == 0) {
		printlg(ERROR_LEVEL, "Did not catch fseek error.\n");
		return 0;
	}

	if (expected_errno != errno) {
		printlg(ERROR_LEVEL,
			"Expected error %d for bad destination, "
			"but got %d.\n",
			expected_errno, errno);
		return 0;
	}

	if (!check_location(buffer, old_location)) {
		printlg(ERROR_LEVEL,
			"Location moved, in spite of failed seek.\n");
		return 0;
	}

	return 1;
}

#pragma GCC diagnostic ignored "-Wunused-parameter"
static int error_read_tester(file_buffer_t *buffer, unsigned char *file_map)
{
	int bad_mode = find_bad_mode();
	if (!test_fseek_error(buffer, 0, bad_mode, EINVAL)) {
		printlg(ERROR_LEVEL, "Did not catch bad mode, %d.\n", bad_mode);
		return 0;
	}

	if (!test_fseek_error(buffer, SMALL_SIZE + 1, SEEK_SET, ERANGE)) {
		printlg(ERROR_LEVEL,
			"Did not detect error when "
			"directly jumping past end of file.\n");
		return 0;
	}

	if (!test_fseek_error(buffer, -1, SEEK_SET, ERANGE)) {
		printlg(ERROR_LEVEL,
			"Did not detect error when "
			"directly jumping to a negative value.\n");
		return 0;
	}

	if (fseek_buffer(buffer, SMALL_SIZE / 2, SEEK_SET)) {
		printlg(ERROR_LEVEL,
			"Failed to jump to the middle of the file.\n");
		return 0;
	}
	if (!test_fseek_error(buffer, SMALL_SIZE, SEEK_CUR, ERANGE)) {
		printlg(ERROR_LEVEL,
			"Did not detect error when "
			"making relative jump past end of file.\n");
		return 0;
	}
	if (!test_fseek_error(buffer, -SMALL_SIZE, SEEK_CUR, ERANGE)) {
		printlg(ERROR_LEVEL,
			"Did not detect error when "
			"making relative jump to a negative destination.\n");
		return 0;
	}


	if (!test_fseek_error(buffer, 1, SEEK_END, ERANGE)) {
		printlg(ERROR_LEVEL,
			"Did not detect error when "
			"jumping past end of file.\n");
		return 0;
	}
	if (!test_fseek_error(buffer, -(SMALL_SIZE + 1), SEEK_END, ERANGE)) {
		printlg(ERROR_LEVEL,
			"Did not detect error when "
			"jumping past beginning of file.\n");
		return 0;
	}

	return 1;
}
#pragma GCC diagnostic error "-Wunused-parameter"

/* Check that invalid calls to "fseek_buffer" are properly reported. */
static struct file_buffer_tv error_read = {
	.file_name = SMALL_FILE,
	.tester = error_read_tester
};

struct file_buffer_tv *file_buffer_tvs[N_FILE_BUFFER_TVS] = {
	&full_read, &segmented_read,
	&small_read, &smaller_read,
	&jumping_read, &error_read
};
示例#9
0
static int
jumping_read_tester(file_buffer_t *buffer, unsigned char *file_map)
{
	/* Jump to the end, and don't expect to read any bytes. */
	if (fseek_buffer(buffer, 0, SEEK_END)) {
		printlg(ERROR_LEVEL, "Failed to jump to end of file.\n");
		return 0;
	}
	if (!check_location(buffer, LARGE_SIZE)) {
		printlg(ERROR_LEVEL, "Failed to reach end of file.\n");
		return 0;
	}
	if (fgetc_buffer(buffer) != EOF) {
		printlg(ERROR_LEVEL,
			"Did not expect to "
			"read a byte at the end of the file.\n");
		return 0;
	}

	/* Read a page, and then read some of the earlier bytes. */
	if (!check_rewind(buffer)) {
		printlg(ERROR_LEVEL, "Failed to rewind from end.\n");
		return 0;
	}
	debug_assert(LARGE_SIZE > PAGE_SIZE);
	if (!read_check(buffer, file_map, PAGE_SIZE, PAGE_SIZE)) {
		printlg(ERROR_LEVEL,
			"Failed to read first page.\n");
		return 0;
	}
#define PAGE_BACK_JUMP	(-PAGE_SIZE * 3 / 4)
	if (fseek_buffer(buffer, -PAGE_BACK_JUMP, SEEK_CUR)) {
		printlg(ERROR_LEVEL,
			"Failed to jump into first page.\n");
		return 0;
	}
	if (!check_location(buffer, PAGE_SIZE - PAGE_BACK_JUMP)) {
		printlg(ERROR_LEVEL,
			"Failed to jump into first page.\n");
		return 0;
	}
	if (!read_check(buffer, file_map, SMALL_SEGMENT, SMALL_SEGMENT)) {
		printlg(ERROR_LEVEL, "Failed to read inside first page.\n");
		return 0;
	}

	/* Rewind, and read part of the first page. */
	if (!check_rewind(buffer)) {
		printlg(ERROR_LEVEL, "Failed to rewind from inside page.\n");
		return 0;
	}
	if (!read_check(buffer, file_map, SMALL_SEGMENT, SMALL_SEGMENT)) {
		printlg(ERROR_LEVEL, "Failed to read beginning.\n");
		return 0;
	}

	/* Read after the first page, and read beginning again. */
	debug_assert(LARGE_SIZE > LARGE_SEGMENT + SMALL_SEGMENT);
	if (fseek_buffer(buffer, LARGE_SEGMENT, SEEK_SET)) {
		printlg(ERROR_LEVEL, "Failed to jump past first page.\n");
		return 0;
	}
	if (!check_location(buffer, LARGE_SEGMENT)) {
		printlg(ERROR_LEVEL,
			"Failed to reach location past first page.\n");
		return 0;
	}
	if (!read_check(buffer, file_map, SMALL_SEGMENT, SMALL_SEGMENT)) {
		printlg(ERROR_LEVEL, "Failed to read after first page.\n");
		return 0;
	}
	if (!check_rewind(buffer)) {
		printlg(ERROR_LEVEL, "Failed to rewind to first page.\n");
		return 0;
	}
	if (!read_check(buffer, file_map, SMALL_SEGMENT, SMALL_SEGMENT)) {
		printlg(ERROR_LEVEL,
			"Failed to read first page "
			"after jumping back to it.\n");
		return 0;
	}


	return 1;
}
示例#10
0
PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t *pamh,
                 int flags,
                 int argc,
                 const char **argv)
{
    struct options *opts;
    FILE *fh;
    char *username;        /* username requesting access */
    char *rhost;           /* remote host */
    char *srv;             /* PAM service we're running as */
    char buf[LINE_LENGTH];
    int retval, action;
    int is_v6 = 0;
    struct locations *geo;
    unsigned char gi_type;

    GeoIP       *gi   = NULL;
#ifdef HAVE_GEOIP_010408
    GeoIP       *gi6  = NULL;
    int is_city6_db   = 0;
#endif
    GeoIPRecord *rec  = NULL;

    opts = malloc(sizeof(struct options));
    if (opts == NULL) {
        pam_syslog(pamh, LOG_CRIT, "malloc error 'opts': %m");
        return PAM_SERVICE_ERR;
    }
    opts->charset      = GEOIP_CHARSET_UTF8;
    opts->debug        = 0;
    opts->action       = PAM_PERM_DENIED;
    opts->system_file  = NULL;
    opts->service_file = NULL;
    opts->by_service   = 0;
    opts->geoip_db     = NULL;
#ifdef HAVE_GEOIP_010408
    opts->use_v6       = 0;
    opts->v6_first     = 0;
    opts->geoip6_db    = NULL;
#endif
    opts->is_city_db   = 0;

    geo = malloc(sizeof(struct locations));
    if (geo == NULL) {
        pam_syslog(pamh, LOG_CRIT, "malloc error 'geo': %m");
        free_opts(opts);
        return PAM_SERVICE_ERR;
    }
    geo->country = NULL;
    geo->city    = NULL;
    geo->next    = NULL;

    _parse_args(pamh, argc, argv, opts);

    if (opts->system_file == NULL)
        opts->system_file = strdup(SYSTEM_FILE);
    if (opts->system_file == NULL) {
        pam_syslog(pamh, LOG_CRIT, "malloc error 'opts->system_file': %m");
        free_opts(opts);
        return PAM_SERVICE_ERR;
    }

    if (opts->geoip_db == NULL)
        opts->geoip_db = strdup(GEOIPDB_FILE);
    if (opts->geoip_db == NULL) {
        pam_syslog(pamh, LOG_CRIT, "malloc error 'opts->geoip_db': %m");
        free_opts(opts);
        return PAM_SERVICE_ERR;
    }

#ifdef HAVE_GEOIP_010408
    if (opts->geoip6_db == NULL)
        opts->geoip6_db = strdup(GEOIP6DB_FILE);
    if (opts->geoip6_db == NULL) {
        pam_syslog(pamh, LOG_CRIT, "malloc error 'opts->geoip6_db': %m");
        free_opts(opts);
        return PAM_SERVICE_ERR;
    }
#endif

    retval = pam_get_item(pamh, PAM_USER, (void*) &username);
    if (username == NULL || retval != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_CRIT, "error recovering username");
        free_opts(opts);
        free_locations(geo);
        return PAM_SERVICE_ERR;
    }

    retval = pam_get_item(pamh, PAM_RHOST, (void*) &rhost);
    if (retval != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_CRIT, "error fetching rhost");
        free_opts(opts);
        free_locations(geo);
        return PAM_SERVICE_ERR;
    }
    if (rhost == NULL) {
        pam_syslog(pamh, LOG_INFO, "rhost is NULL, allowing");
        free_opts(opts);
        free_locations(geo);
        return PAM_SUCCESS;
    }

    retval = pam_get_item(pamh, PAM_SERVICE, (void*) &srv);
    if (srv == NULL || retval != PAM_SUCCESS ) {
        pam_syslog(pamh, LOG_CRIT, "error requesting service name");
        free_opts(opts);
        free_locations(geo);
        return PAM_SERVICE_ERR;
    }

    opts->service_file = malloc(PATH_MAX);
    if (opts->service_file == NULL) {
        pam_syslog(pamh, LOG_CRIT, "malloc error 'service_file': %m");
        free_opts(opts);
        free_locations(geo);
        return PAM_SERVICE_ERR;
    }
    if (snprintf(opts->service_file, PATH_MAX-1, SERVICE_FILE, srv) < 0) {
        pam_syslog(pamh, LOG_CRIT, "snprintf error 'service_file'");
        free_opts(opts);
        free_locations(geo);
        return PAM_SERVICE_ERR;
    }

    gi = GeoIP_open(opts->geoip_db, GEOIP_INDEX_CACHE);
    if (gi == NULL) {
        pam_syslog(pamh, LOG_CRIT,
                   "failed to open geoip db (%s): %m", opts->geoip_db);
        free_opts(opts);
        free_locations(geo);
        return PAM_SERVICE_ERR;
    }
    gi_type = GeoIP_database_edition(gi);
    if (opts->debug)
        pam_syslog(pamh, LOG_DEBUG, "GeoIP edition: %d", gi_type);
    switch (gi_type) {
    case GEOIP_COUNTRY_EDITION:
        if (opts->debug)
            pam_syslog(pamh, LOG_DEBUG, "GeoIP v4 edition: country");
        opts->is_city_db = 0;
        break;
    case GEOIP_CITY_EDITION_REV0:
        if (opts->debug)
            pam_syslog(pamh, LOG_DEBUG, "GeoIP v4 edition: city rev0");
        opts->is_city_db = 1;
        break;
    case GEOIP_CITY_EDITION_REV1:
        if (opts->debug)
            pam_syslog(pamh, LOG_DEBUG, "GeoIP v4 edition: city rev1");
        opts->is_city_db = 1;
        break;
    default:
        pam_syslog(pamh, LOG_CRIT, "invalid GeoIP DB type `%d' found", gi_type);
        GeoIP_delete(gi);
        free_opts(opts);
        free_locations(geo);
        return PAM_SERVICE_ERR;
    }
    GeoIP_set_charset(gi, opts->charset);
    if (opts->debug)
        pam_syslog(pamh, LOG_DEBUG, "GeoIP DB is City: %s",
                   opts->is_city_db ? "yes" : "no");

#ifdef HAVE_GEOIP_010408
    if (opts->use_v6 != 0) {
        gi6 = GeoIP_open(opts->geoip6_db, GEOIP_INDEX_CACHE);
        if (gi6 == NULL) {
            pam_syslog(pamh, LOG_CRIT,
                       "failed to open geoip6 db (%s): %m", opts->geoip6_db);
            GeoIP_delete(gi);
            free_opts(opts);
            free_locations(geo);
            return PAM_SERVICE_ERR;
        }
        gi_type = GeoIP_database_edition(gi6);

        switch (gi_type) {
        case GEOIP_COUNTRY_EDITION_V6:
            if (opts->debug)
                pam_syslog(pamh, LOG_DEBUG, "GeoIP v6 edition: country");
            is_city6_db = 0;
            break;
        case GEOIP_CITY_EDITION_REV0_V6:
            if (opts->debug)
                pam_syslog(pamh, LOG_DEBUG, "GeoIP v6 edition: city rev0");
            is_city6_db = 1;
            break;
        case GEOIP_CITY_EDITION_REV1_V6:
            if (opts->debug)
                pam_syslog(pamh, LOG_DEBUG, "GeoIP v6 edition: city rev1");
            is_city6_db = 1;
            break;
        default:
            pam_syslog(pamh, LOG_CRIT, "invalid GeoIP DB type `%d' found", gi_type);
            GeoIP_delete(gi);
            GeoIP_delete(gi6);
            free_opts(opts);
            free_locations(geo);
            return PAM_SERVICE_ERR;
        }
        if (opts->debug)
            pam_syslog(pamh, LOG_DEBUG, "GeoIP DB is City v6: %s",
                       is_city6_db ? "yes" : "no");
        GeoIP_set_charset(gi6, opts->charset);

        if (opts->is_city_db != is_city6_db) {
            pam_syslog(pamh, LOG_CRIT, "IPv4 DB type is not the same as IPv6 (not both Country edition or both City edition)");
            GeoIP_delete(gi);
            GeoIP_delete(gi6);
            free_opts(opts);
            free_locations(geo);
            return PAM_SERVICE_ERR;
        }

        if (opts->v6_first != 0) {
            rec = GeoIP_record_by_name_v6(gi6, rhost);
            if (rec == NULL) {
                if (opts->debug)
                    pam_syslog(pamh, LOG_DEBUG, "no IPv6 record for %s, trying IPv4", rhost);
                rec = GeoIP_record_by_name(gi, rhost);
            }
            else
                is_v6 = 1;
        }
        else {
            rec = GeoIP_record_by_name(gi, rhost);
            if (rec == NULL) {
                if (opts->debug)
                    pam_syslog(pamh, LOG_DEBUG, "no IPv4 record for %s, trying IPv6", rhost);
                rec = GeoIP_record_by_name_v6(gi6, rhost);
                if (rec != NULL)
                    is_v6 = 1;
            }
        }
    }
    else
#endif /* HAVE_GEOIP_010408 */
        rec = GeoIP_record_by_name(gi, rhost);

    if (rec == NULL) {
        pam_syslog(pamh, LOG_INFO, "no record for %s, setting GeoIP to 'UNKNOWN,*'", rhost);

        geo->city    = strdup("*");
        geo->country = strdup("UNKNOWN");

        if (geo->city == NULL || geo->country == NULL) {
            pam_syslog(pamh, LOG_CRIT, "malloc error 'geo->{city,country}': %m");
            GeoIP_delete(gi);
#ifdef HAVE_GEOIP_010408
            GeoIP_delete(gi6);
#endif
            free_opts(opts);
            free_locations(geo);
            return PAM_SERVICE_ERR;
        }
    }
    else {
        if (rec->city == NULL || opts->is_city_db == 0)
            geo->city = strdup("*");
        else
            geo->city = strdup(rec->city);

        if (rec->country_code == NULL)
            geo->country = strdup("UNKNOWN");
        else
            geo->country = strdup(rec->country_code);

        if (geo->city == NULL || geo->country == NULL) {
            pam_syslog(pamh, LOG_CRIT, "malloc error 'geo->{city,country}': %m");
            GeoIP_delete(gi);
#ifdef HAVE_GEOIP_010408
            GeoIP_delete(gi6);
#endif
            free_opts(opts);
            free_locations(geo);
            return PAM_SERVICE_ERR;
        }

        if (opts->is_city_db) {
            geo->latitude  = rec->latitude;
            geo->longitude = rec->longitude;
        }
    }

    if (opts->debug)
        pam_syslog(pamh, LOG_DEBUG, "GeoIP record for %s: %s,%s",
                   rhost, geo->country, geo->city);

    if (opts->debug && strcmp(geo->country, "UNKNOWN") != 0 && opts->is_city_db)
        pam_syslog(pamh, LOG_DEBUG, "GeoIP coordinates for %s: %f,%f",
                   rhost, geo->latitude, geo->longitude);

    if ((fh = fopen(opts->service_file, "r")) != NULL) {
        opts->by_service = 1;
        if (opts->debug)
            pam_syslog(pamh, LOG_DEBUG, "using services file %s",
                       opts->service_file);
    }
    else {
        if ((fh = fopen(opts->system_file, "r")) == NULL) {
            pam_syslog(pamh, LOG_CRIT, "error opening %s: %m", opts->system_file);

#ifdef HAVE_GEOIP_010408
            if (gi6) GeoIP_delete(gi6);
#endif
            if (gi) GeoIP_delete(gi);
            if (rec) GeoIPRecord_delete(rec);
            free_opts(opts);
            return PAM_SERVICE_ERR;
        }
    }

    action = opts->action;
    char location[LINE_LENGTH];
    while (fgets(buf, LINE_LENGTH, fh) != NULL) {
        char *line, *ptr;
        char domain[LINE_LENGTH],
             service[LINE_LENGTH];

        action = opts->action;
        line   = buf;
        /* skip the leading white space */
        while (*line && isspace(*line))
            line++;

        /* Rip off the comments */
        ptr = strchr(line,'#');
        if (ptr)
            *ptr = '\0';
        /* Rip off the newline char */
        ptr = strchr(line,'\n');
        if (ptr)
            *ptr = '\0';
        /* Anything left ? */
        if (!strlen(line))
            continue;

        if (opts->by_service)
            action = parse_line_srv(pamh, line, domain, location);
        else
            action = parse_line_sys(pamh, line, domain, service, location);
        if (action < 0) { /* parsing failed */
            action = opts->action;
            continue;
        }

        if (!opts->by_service) {
            if (!check_service(pamh, service, srv))
                continue;
        }

        if ((strcmp(domain, "*") == 0) || (strcmp(username, domain) == 0)) {
            if (check_location(pamh, opts, location, geo))
                break;
        }
        else if (domain[0] == '@') {
            if (pam_modutil_user_in_group_nam_nam(pamh, username, domain+1)) {
                if (check_location(pamh, opts, location, geo))
                    break;
            }
        }
    }

    fclose(fh);
    if (gi) GeoIP_delete(gi);
#ifdef HAVE_GEOIP_010408
    if (gi6) GeoIP_delete(gi6);
#endif
    if (rec) GeoIPRecord_delete(rec);
    free_locations(geo);

    switch (action) {
    case PAM_SUCCESS:
        pam_syslog(pamh, LOG_DEBUG, "location %s allowed for user %s from %s (IPv%d)", location, username, rhost, is_v6 ? 6 : 4);
        break;
    case PAM_PERM_DENIED:
        pam_syslog(pamh, LOG_DEBUG, "location %s denied for user %s from %s (IPv%d)", location, username, rhost, is_v6 ? 6 : 4);
        break;
    case PAM_IGNORE:
        pam_syslog(pamh, LOG_DEBUG, "location %s ignored for user %s from %s (IPv%d)", location, username, rhost, is_v6 ? 6 : 4);
        break;
    default: /* should not happen */
        pam_syslog(pamh, LOG_DEBUG, "location status: %d, IPv%d", action, is_v6 ? 6 : 4);
        break;
    };
    free_opts(opts);
    return action;
}