示例#1
0
/*
 * called from bambi to perform index decoding
 *
 * Parse the command line arguments, then call the main decode function
 *
 * returns 0 on success, 1 if there was a problem
 */
int main_seqchksum(int argc, char *argv[])
{
    int ret = 1;

    opts_t* opts = parse_args(argc, argv);
    if (opts) {
        ret = seqchksum(opts);
    }
    free_opts(opts);
    return ret;
}
示例#2
0
文件: ibc.c 项目: vitovitolo/test
int main(int argc, char *argv[]) {
    int err, i;
    struct ibc_opts ibc_opts;
    struct inotify_event *evt;
    char buf[BUF_LEN], output[FILEPATH_BUF_SZ];
    const char *fp;

    memset(&ibc, 0, sizeof(struct ibc));
    err = hcreate_r(HTAB_SIZE, &ibc.htab);
    if (err == 0) {
        perror("hcreate_r");
        goto hcreate_error;
    }

    err = parse_opts(&ibc_opts, argc, argv);
    if (err == -1) {
        goto parsing_error;
    }

    for (i = 0; i < argc; i++)
        memset(argv[i], 0, strlen(argv[i]));


    err = ibc.fd = inotify_init();
    if (err == -1) {
        perror("inotify_init");
        goto inotify_init_error;
    }

    err = add_watches(&ibc_opts);
    if (err == -1) {
        goto add_watches_error;
    }

    while(read(ibc.fd, buf, BUF_LEN) > 0) {
        evt = (struct inotify_event *) buf;
        fp = get_inotify_event_path(evt->wd, evt->name);
        if (fp) {
            snprintf(output, FILEPATH_BUF_SZ, "%s/%s", ibc_opts.output_dir,
                    evt->name);
            cp(output, fp);
        }
    }

add_watches_error:
    close(ibc.fd);
inotify_init_error:
    free_opts(&ibc_opts);
parsing_error:
hcreate_error:
    hdestroy_r(&ibc.htab);
    return err;
}
示例#3
0
文件: ttx.c 项目: djcb/ttx
int
main (int argc, char *argv[])
{
	Opts opts;
	GError *err;
	TTXProviderMgr *prov_mgr;
	int rv;

	if (!setup_l10n ())
		return 1;

	rv	 = 1;
	err	 = NULL;

	prov_mgr = ttx_provider_mgr_new ();

	memset (&opts, 0, sizeof(Opts));

	if (!process_options (&opts, &argc, &argv, &err))
		goto leave;

	if (opts.version)
		return version ();

	if(!get_address_maybe (prov_mgr, &opts, &err))
		goto leave;

	gtk_init (&argc, &argv);

	if (!setup_gui (prov_mgr, &opts))
		goto leave;

	gtk_main ();
	rv = 0;

leave:
	free_opts (&opts);

	ttx_provider_mgr_destroy (prov_mgr);
	if (err) {
		g_printerr ("%s\n", err ? err->message :
			    _("an error occurred"));
		g_clear_error (&err);
	}

	return rv;
}
示例#4
0
int unset_opt(struct opts** opts,const char* name) {
  struct opts *opt=*opts;
  struct opts dummy;
  struct opts *before=&dummy;
  before->next=opt;
  while(opt) {
    if(strcmp(opt->name,name)==0) {
      before->next=opt->next;
      opt->next=NULL;
      free_opts(opt);
      opt=before;
    }
    before=opt;
    opt=opt->next;
  }
  *opts=dummy.next;
  return 1;
}
示例#5
0
文件: main.c 项目: tuhaihe/gtkhash
static void read_opts_postinit(void)
{
    if (opts.files) {
        GSList *uris = NULL;

        for (int i = 0; opts.files[i]; i++)
            uris = g_slist_prepend(uris, filename_arg_to_uri(opts.files[i]));

        uris = g_slist_reverse(uris);

        unsigned int added = gui_add_uris(uris, GUI_VIEW_INVALID);
        if (added == 1)
            gui_set_view(GUI_VIEW_FILE);
        else if (added > 1)
            gui_set_view(GUI_VIEW_FILE_LIST);

        g_slist_free_full(uris, g_free);
    }

    free_opts();
}
示例#6
0
/*
 * Takes the command line options and turns them into something we can understand
 */
static opts_t* parse_args(int argc, char *argv[])
{
    if (argc == 1) { usage(stdout); return NULL; }

    const char* optstring = "i:vb:";

    static const struct option lopts[] = {
        { "hash",                       1, 0, 0 },
        { "input",                      1, 0, 'i' },
        { "verbose",                    0, 0, 'v' },
        { "input-fmt",                  1, 0, 0 },
        { NULL, 0, NULL, 0 }
    };

    opts_t* opts = calloc(sizeof(opts_t), 1);
    if (!opts) { perror("cannot allocate option parsing memory"); return NULL; }

    opts->argv_list = stringify_argv(argc+1, argv-1);
    if (opts->argv_list[strlen(opts->argv_list)-1] == ' ') opts->argv_list[strlen(opts->argv_list)-1] = 0;

    // set defaults
    opts->verbose = false;
    opts->hash = DEFAULT_HASH_TYPE;

    int opt;
    int option_index = 0;
    while ((opt = getopt_long(argc, argv, optstring, lopts, &option_index)) != -1) {
        const char *arg;
        switch (opt) {
        case 'i':   opts->input_name = strdup(optarg);
                    break;
        case 'v':   opts->verbose = true;
                    break;
        case 0:     arg = lopts[option_index].name;
                         if (strcmp(arg, "hash") == 0)               opts->hash = decode_hash_name(optarg);
                    else if (strcmp(arg, "input-fmt") == 0)                  opts->input_fmt = strdup(optarg);
                    else {
                        printf("\nUnknown option: %s\n\n", arg); 
                        usage(stdout); free_opts(opts);
                        return NULL;
                    }
                    break;
        default:    printf("Unknown option: '%c'\n", opt);
            /* else fall-through */
        case '?':   usage(stdout); free_opts(opts); return NULL;
        }
    }

    argc -= optind;
    argv += optind;

    if (argc > 0) opts->input_name = strdup(argv[0]);
    optind = 0;

    // some validation and tidying

    // input defaults to stdin
    if (!opts->input_name) opts->input_name = strdup("-");

    // TODO: list valid hash types here
    if (opts->hash == HASH_UNKNOWN) {
        fprintf(stderr, "Unknown has type\n");
        return NULL;
    }

    return opts;
}
示例#7
0
文件: m_xt_old.c 项目: dtaht/tc-adv
static int
print_ipt(struct action_util *au, FILE * f, struct rtattr *arg)
{
	struct rtattr *tb[TCA_IPT_MAX + 1];
	struct xt_entry_target *t = NULL;

	if (arg == NULL)
		return -1;

	set_lib_dir();

	parse_rtattr_nested(tb, TCA_IPT_MAX, arg);

	if (tb[TCA_IPT_TABLE] == NULL) {
		fprintf(f, "[NULL ipt table name ] assuming mangle ");
	} else {
		fprintf(f, "tablename: %s ",
			rta_getattr_str(tb[TCA_IPT_TABLE]));
	}

	if (tb[TCA_IPT_HOOK] == NULL) {
		fprintf(f, "[NULL ipt hook name ]\n ");
		return -1;
	} else {
		__u32 hook;

		hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
		fprintf(f, " hook: %s\n", ipthooks[hook]);
	}

	if (tb[TCA_IPT_TARG] == NULL) {
		fprintf(f, "\t[NULL ipt target parameters ]\n");
		return -1;
	} else {
		struct xtables_target *m = NULL;

		t = RTA_DATA(tb[TCA_IPT_TARG]);
		m = find_target(t->u.user.name, TRY_LOAD);
		if (m != NULL) {
			if (build_st(m, t) < 0) {
				fprintf(stderr, " %s error\n", m->name);
				return -1;
			}

			opts =
			    merge_options(opts, m->extra_opts,
					  &m->option_offset);
		} else {
			fprintf(stderr, " failed to find target %s\n\n",
				t->u.user.name);
			return -1;
		}
		fprintf(f, "\ttarget ");
		m->print(NULL, m->t, 0);
		if (tb[TCA_IPT_INDEX] == NULL) {
			fprintf(f, " [NULL ipt target index ]\n");
		} else {
			__u32 index;

			index = rta_getattr_u32(tb[TCA_IPT_INDEX]);
			fprintf(f, "\n\tindex %u", index);
		}

		if (tb[TCA_IPT_CNT]) {
			struct tc_cnt *c  = RTA_DATA(tb[TCA_IPT_CNT]);

			fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt);
		}
		if (show_stats) {
			if (tb[TCA_IPT_TM]) {
				struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);

				print_tm(f, tm);
			}
		}
		fprintf(f, "\n");

	}
	free_opts(opts);

	return 0;
}
示例#8
0
文件: m_xt_old.c 项目: dtaht/tc-adv
static int parse_ipt(struct action_util *a, int *argc_p,
		     char ***argv_p, int tca_id, struct nlmsghdr *n)
{
	struct xtables_target *m = NULL;
	struct ipt_entry fw;
	struct rtattr *tail;
	int c;
	int rargc = *argc_p;
	char **argv = *argv_p;
	int argc = 0, iargc = 0;
	char k[FILTER_NAMESZ];
	int size = 0;
	int iok = 0, ok = 0;
	__u32 hook = 0, index = 0;

	set_lib_dir();

	{
		int i;

		for (i = 0; i < rargc; i++) {
			if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) {
				break;
			}
		}
		iargc = argc = i;
	}

	if (argc <= 2) {
		fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc);
		return -1;
	}

	while (1) {
		c = getopt_long(argc, argv, "j:", opts, NULL);
		if (c == -1)
			break;
		switch (c) {
		case 'j':
			m = find_target(optarg, TRY_LOAD);
			if (m != NULL) {

				if (build_st(m, NULL) < 0) {
					printf(" %s error\n", m->name);
					return -1;
				}
				opts =
				    merge_options(opts, m->extra_opts,
						  &m->option_offset);
			} else {
				fprintf(stderr, " failed to find target %s\n\n", optarg);
				return -1;
			}
			ok++;
			break;

		default:
			memset(&fw, 0, sizeof(fw));
			if (m) {
				m->parse(c - m->option_offset, argv, 0,
					 &m->tflags, NULL, &m->t);
			} else {
				fprintf(stderr, " failed to find target %s\n\n", optarg);
				return -1;

			}
			ok++;
			break;

		}
	}

	if (iargc > optind) {
		if (matches(argv[optind], "index") == 0) {
			if (get_u32(&index, argv[optind + 1], 10)) {
				fprintf(stderr, "Illegal \"index\"\n");
				free_opts(opts);
				return -1;
			}
			iok++;

			optind += 2;
		}
	}

	if (!ok && !iok) {
		fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv);
		return -1;
	}

	/* check that we passed the correct parameters to the target */
	if (m)
		m->final_check(m->tflags);

	{
		struct tcmsg *t = NLMSG_DATA(n);

		if (t->tcm_parent != TC_H_ROOT
		    && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) {
			hook = NF_IP_PRE_ROUTING;
		} else {
			hook = NF_IP_POST_ROUTING;
		}
	}

	tail = addattr_nest(n, MAX_MSG, tca_id);
	fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
	fprintf(stdout, "\ttarget: ");

	if (m)
		m->print(NULL, m->t, 0);
	fprintf(stdout, " index %d\n", index);

	if (strlen(tname) > 16) {
		size = 16;
		k[15] = 0;
	} else {
		size = 1 + strlen(tname);
	}
	strncpy(k, tname, size);

	addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size);
	addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4);
	addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
	if (m)
		addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
	addattr_nest_end(n, tail);

	argc -= optind;
	argv += optind;
	*argc_p = rargc - iargc;
	*argv_p = argv;

	optind = 0;
	free_opts(opts);
	/* Clear flags if target will be used again */
        m->tflags = 0;
        m->used = 0;
	/* Free allocated memory */
	if (m->t)
	    free(m->t);


	return 0;

}
示例#9
0
static char *
amfs_parse_defaults(am_node *mp, mntfs *mf, char *def_opts)
{
  char *dflts;
  char *dfl;
  char **rvec = NULL;
  struct mnt_map *mm = (mnt_map *) mf->mf_private;

  dlog("determining /defaults entry value");

  /*
   * Find out if amd.conf overrode any map-specific /defaults.
   */
  if (mm->cfm && mm->cfm->cfm_defaults) {
    dlog("map %s map_defaults override: %s", mf->mf_mount, mm->cfm->cfm_defaults);
    dflts = xstrdup(mm->cfm->cfm_defaults);
  } else if (mapc_search(mm, "/defaults", &dflts) == 0) {
    dlog("/defaults gave %s", dflts);
  } else {
    return def_opts;		/* if nothing found */
  }

  /* trim leading '-' in case thee's one */
  if (*dflts == '-')
    dfl = dflts + 1;
  else
    dfl = dflts;

  /*
   * Chop the defaults up
   */
  rvec = strsplit(dfl, ' ', '\"');

  if (gopt.flags & CFM_SELECTORS_IN_DEFAULTS) {
    /*
     * Pick whichever first entry matched the list of selectors.
     * Strip the selectors from the string, and assign to dfl the
     * rest of the string.
     */
    if (rvec) {
      am_opts ap;
      am_ops *pt;
      char **sp = rvec;
      while (*sp) {		/* loop until you find something, if any */
	memset((char *) &ap, 0, sizeof(am_opts));
	/*
	 * This next routine cause many spurious "expansion of ... is"
	 * messages, which are ignored, b/c all we need out of this
	 * routine is to match selectors.  These spurious messages may
	 * be wrong, esp. if they try to expand ${key} b/c it will
	 * get expanded to "/defaults"
	 */
	pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults",
		       mp->am_parent->am_al->al_mnt->mf_info);
	free_opts(&ap);	/* don't leak */
	if (pt == &amfs_error_ops) {
	  plog(XLOG_MAP, "did not match defaults for \"%s\"", *sp);
	} else {
	  dfl = strip_selectors(*sp, "/defaults");
	  plog(XLOG_MAP, "matched default selectors \"%s\"", dfl);
	  break;
	}
	++sp;
      }
    }
  } else {			/* not selectors_in_defaults */
    /*
     * Extract first value
     */
    dfl = rvec[0];
  }

  /*
   * If there were any values at all...
   */
  if (dfl) {
    /*
     * Log error if there were other values
     */
    if (!(gopt.flags & CFM_SELECTORS_IN_DEFAULTS) && rvec[1]) {
      dlog("/defaults chopped into %s", dfl);
      plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
    }

    /*
     * Prepend to existing defaults if they exist,
     * otherwise just use these defaults.
     */
    if (*def_opts && *dfl) {
      size_t l = strlen(def_opts) + strlen(dfl) + 2;
      char *nopts = (char *) xmalloc(l);
      xsnprintf(nopts, l, "%s;%s", dfl, def_opts);
      XFREE(def_opts);
      def_opts = nopts;
    } else if (*dfl) {
      def_opts = strealloc(def_opts, dfl);
    }
  }

  XFREE(dflts);

  /* don't need info vector any more */
  if (rvec)
    XFREE(rvec);

  return def_opts;
}
示例#10
0
static am_loc *
amfs_lookup_one_location(am_node *new_mp, mntfs *mf, char *ivec,
			char *def_opts, char *pfname)
{
  am_ops *p;
  am_opts *fs_opts;
  am_loc *new_al;
  mntfs *new_mf;
  char *mp_dir = NULL;
#ifdef HAVE_FS_AUTOFS
  int on_autofs = 1;
#endif /* HAVE_FS_AUTOFS */

  /* match the operators */
  /*
   * although we alloc the fs_opts here, the pointer is 'owned' by the am_loc and will
   * be free'd on destruction of the am_loc. If we don't allocate a loc, then we need
   * to free this.
   */
  fs_opts = CALLOC(am_opts);
  p = ops_match(fs_opts, ivec, def_opts, new_mp->am_path,
		pfname, mf->mf_info);
#ifdef HAVE_FS_AUTOFS
  /* XXX: this should be factored out into an autofs-specific function */
  if (new_mp->am_flags & AMF_AUTOFS) {
    /* ignore user-provided fs if we're using autofs */
    if (fs_opts->opt_sublink && fs_opts->opt_sublink[0]) {
      /*
       * For sublinks we need to use a hack with autofs:
       * mount the filesystem on the original opt_fs (which is NOT an
       * autofs mountpoint) and symlink (or lofs-mount) to it from
       * the autofs mountpoint.
       */
      on_autofs = 0;
      mp_dir = fs_opts->opt_fs;
    } else {
      if (p->autofs_fs_flags & FS_ON_AUTOFS) {
	mp_dir = new_mp->am_path;
      } else {
	mp_dir = fs_opts->opt_fs;
	on_autofs = 0;
      }
    }
  } else
#endif /* HAVE_FS_AUTOFS */
    mp_dir = fs_opts->opt_fs;

  /*
   * Find or allocate a filesystem for this node.
   * we search for a matching backend share, since
   * we will construct our own al_loc to handle
   * any customisations for this usage.
   */
  new_mf = find_mntfs(p, fs_opts,
		      mp_dir,
		      fs_opts->fs_mtab,
		      def_opts,
		      fs_opts->opt_opts,
		      fs_opts->opt_remopts);


  /*
   * See whether this is a real filesystem
   */
  p = new_mf->mf_ops;
  if (p == &amfs_error_ops) {
    plog(XLOG_MAP, "Map entry %s for %s did not match", ivec, new_mp->am_path);
    free_mntfs(new_mf);
    free_opts(fs_opts);
    XFREE(fs_opts);
    return NULL;
  }

  dlog("Got a hit with %s", p->fs_type);
  new_al = new_loc();
  free_mntfs(new_al->al_mnt);
  new_al->al_mnt = new_mf;
  new_al->al_fo = fs_opts; /* now the loc is in charge of free'ing this mem */

#ifdef HAVE_FS_AUTOFS
  if (new_mp->am_flags & AMF_AUTOFS && on_autofs) {
    new_mf->mf_flags |= MFF_ON_AUTOFS;
    new_mf->mf_fsflags = new_mf->mf_ops->autofs_fs_flags;
  }
  /*
   * A new filesystem is an autofs filesystems if:
   * 1. it claims it can be one (has the FS_AUTOFS flag)
   * 2. autofs is enabled system-wide
   * 3. either has an autofs parent,
   *    or it is explicitly requested to be autofs.
   */
  if (new_mf->mf_ops->autofs_fs_flags & FS_AUTOFS &&
      amd_use_autofs &&
      ((mf->mf_flags & MFF_IS_AUTOFS) ||
       (new_mf->mf_fo && new_mf->mf_fo->opt_mount_type &&
	STREQ(new_mf->mf_fo->opt_mount_type, "autofs"))))
    new_mf->mf_flags |= MFF_IS_AUTOFS;
#endif /* HAVE_FS_AUTOFS */

  return new_al;
}
示例#11
0
文件: opts.c 项目: AzerTyQsdF/osx
int
eval_fs_opts(am_opts *fo, char *opts, char *g_opts, char *path, char *key, char *map)
{
  int ok = TRUE;

  free_opts(fo);

  /*
   * Clear out the option table
   */
  memset((voidp) &fs_static, 0, sizeof(fs_static));
  memset((voidp) vars, 0, sizeof(vars));
  memset((voidp) fo, 0, sizeof(*fo));

  /* set hostname */
  opt_host = (char *) am_get_hostname();

  /*
   * Set key, map & path before expansion
   */
  opt_key = key;
  opt_map = map;
  opt_path = path;

  opt_dkey = strchr(key, '.');
  if (!opt_dkey) {
    opt_dkey = NullStr;
    opt_keyd = key;
  } else {
    opt_keyd = strnsave(key, opt_dkey - key);
    opt_dkey++;
    if (*opt_dkey == '\0')	/* check for 'host.' */
      opt_dkey = NullStr;
  }

  /*
   * Expand global options
   */
  fs_static.fs_glob = expand_selectors(g_opts);

  /*
   * Expand local options
   */
  fs_static.fs_local = expand_selectors(opts);

  /* break global options into fs_static fields */
  if ((ok = split_opts(fs_static.fs_glob, key))) {
    dlog("global split_opts ok");
    /*
     * evaluate local selectors
     */
    if ((ok = eval_selectors(fs_static.fs_local, key))) {
      dlog("local eval_selectors ok");
      /* if the local selectors matched, then do the local overrides */
      ok = split_opts(fs_static.fs_local, key);
      if (ok)
	dlog("local split_opts ok");
    }
  }

  /*
   * Normalize remote host name.
   * 1.  Expand variables
   * 2.  Normalize relative to host tables
   * 3.  Strip local domains from the remote host
   *     name before using it in other expansions.
   *     This makes mount point names and other things
   *     much shorter, while allowing cross domain
   *     sharing of mount maps.
   */
  apply_opts(expand_opts, rhost_expansion, FALSE);
  if (ok && fs_static.opt_rhost && *fs_static.opt_rhost)
    host_normalize(&fs_static.opt_rhost);

  /*
   * Macro expand the options.
   * Do this regardless of whether we are accepting
   * this mount - otherwise nasty things happen
   * with memory allocation.
   */
  apply_opts(expand_opts, expansions, FALSE);

  /*
   * Strip trailing slashes from local pathname...
   */
  deslashify(fs_static.opt_fs);

  /*
   * ok... copy the data back out.
   */
  *fo = fs_static;

  /*
   * Clear defined options
   */
  if (opt_keyd != key && opt_keyd != nullstr)
    XFREE(opt_keyd);
  opt_keyd = nullstr;
  opt_dkey = NullStr;
  opt_key = opt_map = opt_path = nullstr;

  return ok;
}
示例#12
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;
}