Esempio n. 1
0
void server_loop(int fd)
{
	struct timeval snaptime = { 0 };
	struct pollfd p;
	p.fd = fd;
	p.events = p.revents = POLLIN;

	sprintf(info_source, "%d.%lu sampling_interval=%d time_const=%d",
		getpid(), (unsigned long)random(), scan_interval/1000, time_constant/1000);

	load_info();

	for (;;) {
		int status;
		int tdiff;
		struct timeval now;

		gettimeofday(&now, NULL);
		tdiff = T_DIFF(now, snaptime);
		if (tdiff >= scan_interval) {
			update_db(tdiff);
			snaptime = now;
			tdiff = 0;
		}

		if (poll(&p, 1, tdiff + scan_interval) > 0
		    && (p.revents&POLLIN)) {
			int clnt = accept(fd, NULL, NULL);
			if (clnt >= 0) {
				pid_t pid;
				if (children >= 5) {
					close(clnt);
				} else if ((pid = fork()) != 0) {
					if (pid>0)
						children++;
					close(clnt);
				} else {
					FILE *fp = fdopen(clnt, "w");
					if (fp) {
						if (tdiff > 0)
							update_db(tdiff);
						dump_raw_db(fp, 0);
					}
					exit(0);
				}
			}
		}
		while (children && waitpid(-1, &status, WNOHANG) > 0)
			children--;
	}
}
Esempio n. 2
0
/**
 * Main entry.
 */
int main(int argc, char **argv)
{
        autofree(GError) *error = NULL;
        autofree(GOptionContext) *context = NULL;
        int ret = EXIT_FAILURE;

        LIBXML_TEST_VERSION
        context = g_option_context_new(" - cve update");
        g_option_context_add_main_entries(context, _entries, NULL);
        if (!g_option_context_parse(context, &argc, &argv, &error)) {
                g_printerr("Invalid options: %s\n", error->message);
                goto end;
        }

        if (_show_version) {
                show_version();
                ret = EXIT_SUCCESS;
                goto end;
        }

        if (update_db(_quiet)) {
                ret = EXIT_SUCCESS;
        } else {
                fprintf(stderr, "Failed to update database\n");
        }

end:
        xmlCleanupParser();
        return ret;
}
Esempio n. 3
0
/*
*	用于将编译运行后的结果反馈到数据库中,注意从相应文件中读取反馈时,
*   文件内容中不能有单引号
*/
void update_ret_to_db() {
	char *buf;
	char sql[LONG_SQL_LEN] = {0};
	int ret, fz;

	buf = readfile(CE_OUT, &fz);
	if (fz) {
		snprintf(sql,LONG_SQL_LEN, "update code set ce_result='%s' \
			where code_id='%s'", buf, code_id);
		free(buf);
		update_db(sql);
	} else {
Esempio n. 4
0
File: tree.c Progetto: teknotry/DMMD
int update_tree(int index,struct yyy *d,int st)
{
	
	int i,j,start;
	if(index>no*no)
	{
		printf("Invalid Index\n");
		return 0;
	}

	v=root;
	i=0;
	while(v->index[i]<index)
	{
		if(i==no)
			break;
	//	printf("%d  %d\n",v->index[i],i);
		i++;
	//	sleep(1);
	}
	if(v->index[i]!=index)
	{
		i--;
	}
	
	v=v->ad[i];

	if(v->data[index%no]->st==1)
	{	
		v->data[index%no]=malloc(sizeof(struct data));
		//Data assignment............
	
	
		v->data[index%no]->roll=d->roll;
		v->data[index%no]->st=st;
		strcpy(v->data[index%no]->name,d->name);
		strcpy(v->data[index%no]->branch,d->branch);
		strcpy(v->data[index%no]->mobno,d->mobno);
		v->data[index%no]->st=1;
		printf("NOT IN DB\n");
	}
	else
	{
		
		strcpy(v->data[index%no]->name,d->name);
		strcpy(v->data[index%no]->branch,d->branch);
		strcpy(v->data[index%no]->mobno,d->mobno);
		v->data[index%no]->st=0;
		update_db(d->name,d->roll,d->branch,d->mobno);
		printf(" IN DB\n");
	}
}
Esempio n. 5
0
int do_update_merchants(int param)
{
	int c;
	MERCHANTS merchants;
	char tmp[INFO_MAXINPUT + 1];

	LOG(LOG_DEBUG, "执行修改商户信息功能...");
	memset(&merchants, 0, sizeof(merchants));
INPUT_MID:
	printf("请输入[修改]商户编号:");
	scanf("%s", tmp);
	while((c = getchar()) != '\n' && c != EOF);//清空缓存
	if (strlen(tmp) != MID_SIZE || !isdigits(tmp, strlen(tmp))) {
		printf("输入数据必须是%d个数字!\n", MID_SIZE);
		goto INPUT_MID;
	}
	memcpy(merchants.mid, tmp, strlen(tmp));
INPUT_TID:
	printf("请输入终端编号:");
	scanf("%s", tmp);
	while((c = getchar()) != '\n' && c != EOF);//清空缓存
	if (strlen(tmp) != TID_SIZE || !isdigits(tmp, strlen(tmp))) {
		printf("输入数据必须是%d个数字!\n", TID_SIZE);
		goto INPUT_TID;
	}
	memcpy(merchants.tid, tmp, strlen(tmp));
INPUT_MNAME:
	printf("请输入商户名称:");
	scanf("%s", tmp);
	while((c = getchar()) != '\n' && c != EOF);//清空缓存
	if (strlen(tmp) > MNAME_MAXSIZE) {
		printf("输入数据不能超过%d个字节!\n", MNAME_MAXSIZE);
		goto INPUT_MNAME;
	}
	memcpy(merchants.mname, tmp, strlen(tmp));
INPUT_MMENU:
	printf("请输入商户菜单:");
	scanf("%s", tmp);
	while((c = getchar()) != '\n' && c != EOF);//清空缓存
	if (strlen(tmp) > MMENU_MAXSIZE) {
		printf("输入数据不能超过%d个字节!\n", MMENU_MAXSIZE);
		goto INPUT_MMENU;
	}
	memcpy(merchants.mmenu, tmp, strlen(tmp));
	if (!update_db(IT_MERCHANTS, merchants.mid, MEMBERS_COUNT, merchants.mid, merchants.tid, merchants.mname, merchants.mmenu)) {
		printf("修改商户:%s失败!\n", merchants.mid);
		return -1;
	} else {
		printf("修改商户:%s成功。\n", merchants.mid);
		return 0;
	}
}
Esempio n. 6
0
/*
 * Create a symlink called compat_link that points to target.
 * If it already exists correctly don't do anything.  If it
 * exists but is incorrect, delete the link and make it.  If
 * it doesn't exist just make it.
 */
static void
make_link(
	char *compat_link,
	char *target,
	struct symlink *compat_slp,
	int link_type)
{
	if (compat_slp->target != NULL) {
		if (strcmp(target, compat_slp->target) == 0) {
			if (debug)
				(void) printf("already %s -> %s\n",
				    compat_link, compat_slp->target);
			update_db(compat_link, target, link_type);
			return;
		} else {
			if (debug)
				(void) printf("remove %s, link wrong (%s)\n",
				    compat_link, compat_slp->target);
			else {
				if (unlink(compat_link) == -1)
					xperror(compat_link);
				else
					(void) di_devlink_rm_link(link_handle,
					    compat_link);
			}
			compat_slp->target = target;
		}
	} else
		compat_slp->target = target;

	if (debug)
		(void) printf("link %s -> %s\n", compat_link, target);
	else {
		if (symlink(target, compat_link) == -1)
			xperror(compat_link);
		else
			update_db(compat_link, target, link_type);
	}
}
Esempio n. 7
0
void
process_trans (void)
{
	struct trans *tp;
	int idx;
	char buf[1000];
	SHA_CTX ctx;
	char *outp;

	trans_arr = xcalloc (ntrans, sizeof *trans_arr);
	for (tp = trans_list, idx = 0; tp; tp = tp->next, idx++)
		trans_arr[idx] = tp;

	for (tp = trans_list; tp; tp = tp->next) {
		SHA1_Init (&ctx);
		SHA1_Update (&ctx, tp->ref, strlen (tp->ref));
		SHA1_Update (&ctx, tp->posted, strlen (tp->posted));
		SHA1_Update (&ctx, tp->name, strlen (tp->name));
		SHA1_Update (&ctx, tp->memo, strlen (tp->memo));
		sprintf (buf, "%.2f", tp->amount);
		SHA1_Update (&ctx, buf, strlen (buf));
		SHA1_Final (tp->hash, &ctx);
	}

	qsort (trans_arr, ntrans, sizeof *trans_arr, hash_cmp);
	
	for (idx = 0; idx < ntrans - 1; idx++) {
		if (memcmp (trans_arr[idx]->hash,
			    trans_arr[idx+1]->hash,
			    SHA_DIGEST_LENGTH) == 0) {
			trans_arr[idx+1]->dayseq = trans_arr[idx]->dayseq + 1;
		}
	}

	for (tp = trans_list; tp; tp = tp->next) {
		outp = buf;
		for (idx = 0; idx < 4; idx++) {
			sprintf (outp, "%02x", tp->hash[idx]);
			outp += 2;
		}
		sprintf (outp, "-%02d", tp->dayseq);
		tp->trans_id = xstrdup (buf);
	}

	for (tp = trans_list; tp; tp = tp->next)
		print_trans (stdout, tp);

	for (tp = trans_list; tp; tp = tp->next)
		update_db (tp);
}
Esempio n. 8
0
static void
add_file(char *dbname, char *name, int fresh)
{
    char fullname[256];
    char temp_db_file[256];
    FILE *db_fp = NULL;
    FILE *temp_db_fp = NULL;
    FILE *ht_fp = NULL;
    char addname[100];
    /*char *HTPATH;*/
    /*char *trace;*/
    /*char *spad;*/


    /** First thing I should do is find the proper file and open it **/
    ht_fp = ht_file_open(fullname, addname, name);

    /*
     * Now I should try to open the two database files. The one to work with,
     * and the temporary one; Send it a 1 so it checks for write access
     */
    if (fresh) {
        if ((db_fp = fopen(dbname, "a")) == NULL) {
            fprintf(stderr, "Can't open database: %s file for appending\n", dbname);
            exit(-1);
        }
    }
    else {
        if ((db_fp = fopen(dbname, "r")) == NULL) {
        }
    }
    if (!fresh)
        temp_db_fp = temp_file_open(temp_db_file);

    /** Now actually update the file by adding the changes ***/
    update_db(db_fp, temp_db_fp, ht_fp, addname, fullname, fresh);

    if (!fresh)
        fclose(temp_db_fp);
    fclose(ht_fp);
    if (db_fp != NULL)
        fclose(db_fp);
    if (!fresh) {
        copy_file(temp_db_file, dbname);
        unlink(temp_db_file);
    }
}
Esempio n. 9
0
int check_user_token(char *user, char *token, sqlite3 *db)
{
  char *request;
  sqlite3_stmt *ppStmt;
  entry_st entry;
  yubikey_token_st tok;
  int id, rc;

  request = sqlite3_mprintf("SELECT id FROM tokens WHERE user=%Q;", user);

  rc = sqlite3_prepare_v2(db, request, -1,
			  &ppStmt, NULL);
  sqlite3_free(request);
  if(check_error("Error in preparing SELECT", rc, db))
    return CHK_FAIL;

  rc = sqlite3_step(ppStmt);
  if (rc != SQLITE_ROW)
    {
      sqlite3_finalize(ppStmt);
      return CHK_UNKNOWN;
    }
 if (strlen(token) != 32)
   {
     sqlite3_finalize(ppStmt);
     return CHK_FAIL;
   }

  while (rc == SQLITE_ROW)
    {
      id = sqlite3_column_int(ppStmt, 0);
      get_entry_from_id(id, &entry, db);
      yubikey_parse ((uint8_t *) token, entry.aes_bin, &tok);
      rc = check_token(&tok, entry.uid, entry.counter, entry.session);
      if (rc == CHK_OK)
	{
	  rc = update_db(db, id, &tok);
	  sqlite3_finalize(ppStmt);
	  return rc;
	}
      rc = sqlite3_step(ppStmt);
    }
  sqlite3_finalize(ppStmt);
  return CHK_FAIL;
}
Esempio n. 10
0
static void budgie_media_view_set_property(GObject *object,
                                           guint prop_id,
                                           const GValue *value,
                                           GParamSpec *pspec)
{
        BudgieMediaView *self;

        self = BUDGIE_MEDIA_VIEW(object);
        switch (prop_id) {
                case PROP_DATABASE:
                        self->db = g_value_get_pointer((GValue*)value);
                        update_db(self);
                        break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
                                prop_id, pspec);
                        break;
        }
}
Esempio n. 11
0
/* Update the disclose database, adding when rm is zero, removing otherwise.
 * Documented in detail in poolback.h
 */
int update_disclose (struct pulleyback_tlspool *self, uint8_t **data, int rm) {
	dercursor lid;
	dercursor rid;
	lid.derlen = rid.derlen = 1030;  // Sane upper margin (errors beyond)
	lid.derptr = (uint8_t *) fetch_value (self, MXG_LOCALID , data);
	rid.derptr = (uint8_t *) fetch_value (self, MXG_REMOTEID, data);
	assert (lid.derptr != NULL);
	assert (rid.derptr != NULL);
	if (der_enter (&lid) || der_enter (&rid)) {
		// Perhaps length is too small, or DER formatting error
		return 0;
	}
	printf ("Updating disclose.db (%s): %.*s -> %.*s\n",
		rm ? "DEL" : "ADD",
		 (int)rid.derlen,
		 rid.derptr,
		 (int)lid.derlen,
		 lid.derptr
	);
	return update_db (self, &rid, &lid, -1, NULL, rm);
}
Esempio n. 12
0
int data_one_from_db (char *dataname)
{

	struct weblink * link;

	init_sqlite(dataname);
	
	link = get_a_record();
	if (link == NULL)
        {
		db_close ();
		return 0;
	}
	use_domain = link->domain;	
        use_page   = link->page;
	data_from_web (link->domain,link->page);
	update_db(link->id,2);

	free(link->page);
	
	db_close ();
	
	return 1;
}
Esempio n. 13
0
*/
void update_ret_to_db() {
	char *buf;
	char sql[LONG_SQL_LEN] = {0};
	int ret, fz;

	buf = readfile(CE_OUT, &fz);
	if (fz) {
		snprintf(sql,LONG_SQL_LEN, "update code set ce_result='%s' \
			where code_id='%s'", buf, code_id);
		free(buf);
		update_db(sql);
	} else {
		snprintf(sql,LONG_SQL_LEN, "update code set ce_result='%s' \
			where code_id='%s'", "", code_id);
		update_db(sql);
	}

	buf = readfile(RE_OUT, &fz);
	if (fz) {
		snprintf(sql,LONG_SQL_LEN, "update code set re_result='%s' \
			where code_id='%s'", buf, code_id);
		free(buf);
		update_db(sql);
	} else {
		snprintf(sql,LONG_SQL_LEN, "update code set re_result='%s' \
			where code_id='%s'", "", code_id);
		update_db(sql);
	}

	buf = readfile(DATA_OUT, &fz);
Esempio n. 14
0
int
main(int argc, char *argv[])
{
	struct group *gr;
	struct stat st;
	int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
	uid_t uid, saved_uid;
	gid_t saved_gid, saved_gids[NGROUPS_MAX];
	int nsaved_gids;
#ifdef notdef
	char *domain;
#endif
	char *p, *ttyn;
	const char *pwprompt;
	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
	char localhost[MAXHOSTNAMELEN + 1];
	int need_chpass, require_chpass;
	int login_retries = DEFAULT_RETRIES, 
	    login_backoff = DEFAULT_BACKOFF;
	time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
	char *loginname = NULL;
#ifdef KERBEROS5
	int Fflag;
	krb5_error_code kerror;
#endif
#if defined(KERBEROS5)
	int got_tickets = 0;
#endif
#ifdef LOGIN_CAP
	char *shell = NULL;
	login_cap_t *lc = NULL;
#endif

	tbuf[0] = '\0';
	rval = 0;
	pwprompt = NULL;
	nested = NULL;
	need_chpass = require_chpass = 0;

	(void)signal(SIGALRM, timedout);
	(void)alarm(timeout);
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGINT, SIG_IGN);
	(void)setpriority(PRIO_PROCESS, 0, 0);

	openlog("login", 0, LOG_AUTH);

	/*
	 * -p is used by getty to tell login not to destroy the environment
	 * -f is used to skip a second login authentication
	 * -h is used by other servers to pass the name of the remote host to
	 *    login so that it may be placed in utmp/utmpx and wtmp/wtmpx
	 * -a in addition to -h, a server may supply -a to pass the actual
	 *    server address.
	 * -s is used to force use of S/Key or equivalent.
	 */
	if (gethostname(localhost, sizeof(localhost)) < 0) {
		syslog(LOG_ERR, "couldn't get local hostname: %m");
		strcpy(hostname, "amnesiac");
	}
#ifdef notdef
	domain = strchr(localhost, '.');
#endif
	localhost[sizeof(localhost) - 1] = '\0';

	fflag = hflag = pflag = sflag = 0;
	have_ss = 0;
#ifdef KERBEROS5
	Fflag = 0;
	have_forward = 0;
#endif
	uid = getuid();
	while ((ch = getopt(argc, argv, "a:Ffh:ps")) != -1)
		switch (ch) {
		case 'a':
			if (uid)
				errx(EXIT_FAILURE, "-a option: %s", strerror(EPERM));
			decode_ss(optarg);
#ifdef notdef
			(void)sockaddr_snprintf(optarg,
			    sizeof(struct sockaddr_storage), "%a", (void *)&ss);
#endif
			break;
		case 'F':
#ifdef KERBEROS5
			Fflag = 1;
#endif
			/* FALLTHROUGH */
		case 'f':
			fflag = 1;
			break;
		case 'h':
			if (uid)
				errx(EXIT_FAILURE, "-h option: %s", strerror(EPERM));
			hflag = 1;
#ifdef notdef
			if (domain && (p = strchr(optarg, '.')) != NULL &&
			    strcasecmp(p, domain) == 0)
				*p = '\0';
#endif
			hostname = optarg;
			break;
		case 'p':
			pflag = 1;
			break;
		case 's':
			sflag = 1;
			break;
		default:
		case '?':
			usage();
			break;
		}

	setproctitle(NULL);
	argc -= optind;
	argv += optind;

	if (*argv) {
		username = loginname = *argv;
		ask = 0;
	} else
		ask = 1;

#ifdef F_CLOSEM
	(void)fcntl(3, F_CLOSEM, 0);
#else
	for (cnt = getdtablesize(); cnt > 2; cnt--)
		(void)close(cnt);
#endif

	ttyn = ttyname(STDIN_FILENO);
	if (ttyn == NULL || *ttyn == '\0') {
		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
		ttyn = tname;
	}
	if ((tty = strstr(ttyn, "/pts/")) != NULL)
		++tty;
	else if ((tty = strrchr(ttyn, '/')) != NULL)
		++tty;
	else
		tty = ttyn;

	if (issetugid()) {
		nested = strdup(user_from_uid(getuid(), 0));
		if (nested == NULL) {
			syslog(LOG_ERR, "strdup: %m");
			sleepexit(EXIT_FAILURE);
		}
	}

#ifdef LOGIN_CAP
	/* Get "login-retries" and "login-backoff" from default class */
	if ((lc = login_getclass(NULL)) != NULL) {
		login_retries = (int)login_getcapnum(lc, "login-retries",
		    DEFAULT_RETRIES, DEFAULT_RETRIES);
		login_backoff = (int)login_getcapnum(lc, "login-backoff", 
		    DEFAULT_BACKOFF, DEFAULT_BACKOFF);
		login_close(lc);
		lc = NULL;
	}
#endif

#ifdef KERBEROS5
	kerror = krb5_init_context(&kcontext);
	if (kerror) {
		/*
		 * If Kerberos is not configured, that is, we are
		 * not using Kerberos, do not log the error message.
		 * However, if Kerberos is configured,  and the
		 * context init fails for some other reason, we need
		 * to issue a no tickets warning to the user when the
		 * login succeeds.
		 */
		if (kerror != ENXIO) {	/* XXX NetBSD-local Heimdal hack */
			syslog(LOG_NOTICE,
			    "%s when initializing Kerberos context",
			    error_message(kerror));
			krb5_configured = 1;
		}
		login_krb5_get_tickets = 0;
	}
#endif /* KERBEROS5 */

	for (cnt = 0;; ask = 1) {
#if defined(KERBEROS5)
		if (login_krb5_get_tickets)
			k5destroy();
#endif
		if (ask) {
			fflag = 0;
			loginname = getloginname();
		}
		rootlogin = 0;
#ifdef KERBEROS5
		if ((instance = strchr(loginname, '/')) != NULL)
			*instance++ = '\0';
		else
			instance = __UNCONST("");
#endif
		username = trimloginname(loginname);
		/*
		 * Note if trying multiple user names; log failures for
		 * previous user name, but don't bother logging one failure
		 * for nonexistent name (mistyped username).
		 */
		if (failures && strcmp(tbuf, username)) {
			if (failures > (pwd ? 0 : 1))
				badlogin(tbuf);
			failures = 0;
		}
		(void)strlcpy(tbuf, username, sizeof(tbuf));

		pwd = getpwnam(username);

#ifdef LOGIN_CAP
		/*
		 * Establish the class now, before we might goto
		 * within the next block. pwd can be NULL since it
		 * falls back to the "default" class if it is.
		 */
		lc = login_getclass(pwd ? pwd->pw_class : NULL);
#endif
		/*
		 * if we have a valid account name, and it doesn't have a
		 * password, or the -f option was specified and the caller
		 * is root or the caller isn't changing their uid, don't
		 * authenticate.
		 */
		if (pwd) {
			if (pwd->pw_uid == 0)
				rootlogin = 1;

			if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
				/* already authenticated */
#ifdef KERBEROS5
				if (login_krb5_get_tickets && Fflag)
					k5_read_creds(username);
#endif
				break;
			} else if (pwd->pw_passwd[0] == '\0') {
				/* pretend password okay */
				rval = 0;
				goto ttycheck;
			}
		}

		fflag = 0;

		(void)setpriority(PRIO_PROCESS, 0, -4);

#ifdef SKEY
		if (skey_haskey(username) == 0) {
			static char skprompt[80];
			const char *skinfo = skey_keyinfo(username);
				
			(void)snprintf(skprompt, sizeof(skprompt),
			    "Password [ %s ]:",
			    skinfo ? skinfo : "error getting challenge");
			pwprompt = skprompt;
		} else
#endif
			pwprompt = "Password:"******"Login incorrect or refused on this "
			    "terminal.\n");
			if (hostname)
				syslog(LOG_NOTICE,
				    "LOGIN %s REFUSED FROM %s ON TTY %s",
				    pwd->pw_name, hostname, tty);
			else
				syslog(LOG_NOTICE,
				    "LOGIN %s REFUSED ON TTY %s",
				     pwd->pw_name, tty);
			continue;
		}

		if (pwd && !rval)
			break;

		(void)printf("Login incorrect or refused on this "
		    "terminal.\n");
		failures++;
		cnt++;
		/*
		 * We allow login_retries tries, but after login_backoff
		 * we start backing off.  These default to 10 and 3
		 * respectively.
		 */
		if (cnt > login_backoff) {
			if (cnt >= login_retries) {
				badlogin(username);
				sleepexit(EXIT_FAILURE);
			}
			sleep((u_int)((cnt - login_backoff) * 5));
		}
	}

	/* committed to login -- turn off timeout */
	(void)alarm((u_int)0);

	endpwent();

	/* if user not super-user, check for disabled logins */
#ifdef LOGIN_CAP
	if (!login_getcapbool(lc, "ignorenologin", rootlogin))
		checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
#else
	if (!rootlogin)
		checknologin(NULL);
#endif

#ifdef LOGIN_CAP
	quietlog = login_getcapbool(lc, "hushlogin", 0);
#else
	quietlog = 0;
#endif
	/* Temporarily give up special privileges so we can change */
	/* into NFS-mounted homes that are exported for non-root */
	/* access and have mode 7x0 */
	saved_uid = geteuid();
	saved_gid = getegid();
	nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
	
	(void)setegid(pwd->pw_gid);
	initgroups(username, pwd->pw_gid);
	(void)seteuid(pwd->pw_uid);
	
	if (chdir(pwd->pw_dir) < 0) {
#ifdef LOGIN_CAP
		if (login_getcapbool(lc, "requirehome", 0)) {
			(void)printf("Home directory %s required\n",
			    pwd->pw_dir);
			sleepexit(EXIT_FAILURE);
		}
#endif	
		(void)printf("No home directory %s!\n", pwd->pw_dir);
		if (chdir("/") == -1)
			exit(EXIT_FAILURE);
		pwd->pw_dir = __UNCONST("/");
		(void)printf("Logging in with home = \"/\".\n");
	}

	if (!quietlog)
		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;

	/* regain special privileges */
	(void)seteuid(saved_uid);
	setgroups(nsaved_gids, saved_gids);
	(void)setegid(saved_gid);

#ifdef LOGIN_CAP
	pw_warntime = login_getcaptime(lc, "password-warn",
		_PASSWORD_WARNDAYS * SECSPERDAY,
		_PASSWORD_WARNDAYS * SECSPERDAY);
#endif

	(void)gettimeofday(&now, NULL);
	if (pwd->pw_expire) {
		if (now.tv_sec >= pwd->pw_expire) {
			(void)printf("Sorry -- your account has expired.\n");
			sleepexit(EXIT_FAILURE);
		} else if (pwd->pw_expire - now.tv_sec < pw_warntime && 
		    !quietlog)
			(void)printf("Warning: your account expires on %s",
			    ctime(&pwd->pw_expire));
	}
	if (pwd->pw_change) {
		if (pwd->pw_change == _PASSWORD_CHGNOW)
			need_chpass = 1;
		else if (now.tv_sec >= pwd->pw_change) {
			(void)printf("Sorry -- your password has expired.\n");
			sleepexit(EXIT_FAILURE);
		} else if (pwd->pw_change - now.tv_sec < pw_warntime && 
		    !quietlog)
			(void)printf("Warning: your password expires on %s",
			    ctime(&pwd->pw_change));

	}
	/* Nothing else left to fail -- really log in. */
	update_db(quietlog, rootlogin, fflag);

	(void)chown(ttyn, pwd->pw_uid,
	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);

	if (ttyaction(ttyn, "login", pwd->pw_name))
		(void)printf("Warning: ttyaction failed.\n");

#if defined(KERBEROS5)
	/* Fork so that we can call kdestroy */
	if (! login_krb5_retain_ccache && has_ccache)
		dofork();
#endif

	/* Destroy environment unless user has requested its preservation. */
	if (!pflag)
		environ = envinit;

#ifdef LOGIN_CAP
	if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid,
	    LOGIN_SETLOGIN) != 0) {
		syslog(LOG_ERR, "setusercontext failed");
		exit(EXIT_FAILURE);
	}
	if (setusercontext(lc, pwd, pwd->pw_uid,
	    (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) {
		syslog(LOG_ERR, "setusercontext failed");
		exit(EXIT_FAILURE);
	}
#else
	(void)setgid(pwd->pw_gid);

	initgroups(username, pwd->pw_gid);
	
	if (nested == NULL && setlogin(pwd->pw_name) < 0)
		syslog(LOG_ERR, "setlogin() failure: %m");

	/* Discard permissions last so can't get killed and drop core. */
	if (rootlogin)
		(void)setuid(0);
	else
		(void)setuid(pwd->pw_uid);
#endif

	if (*pwd->pw_shell == '\0')
		pwd->pw_shell = __UNCONST(_PATH_BSHELL);
#ifdef LOGIN_CAP
	if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) {
		if ((shell = strdup(shell)) == NULL) {
			syslog(LOG_ERR, "Cannot alloc mem");
			sleepexit(EXIT_FAILURE);
		}
		pwd->pw_shell = shell;
	}
#endif
	
	(void)setenv("HOME", pwd->pw_dir, 1);
	(void)setenv("SHELL", pwd->pw_shell, 1);
	if (term[0] == '\0') {
		const char *tt = stypeof(tty);
#ifdef LOGIN_CAP
		if (tt == NULL)
			tt = login_getcapstr(lc, "term", NULL, NULL);
#endif
		/* unknown term -> "su" */
		(void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term));
	}
	(void)setenv("TERM", term, 0);
	(void)setenv("LOGNAME", pwd->pw_name, 1);
	(void)setenv("USER", pwd->pw_name, 1);

#ifdef LOGIN_CAP
	setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
#else
	(void)setenv("PATH", _PATH_DEFPATH, 0);
#endif

#ifdef KERBEROS5
	if (krb5tkfile_env)
		(void)setenv("KRB5CCNAME", krb5tkfile_env, 1);
#endif

	/* If fflag is on, assume caller/authenticator has logged root login. */
	if (rootlogin && fflag == 0) {
		if (hostname)
			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
			    username, tty, hostname);
		else
			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
			    username, tty);
	}

#if defined(KERBEROS5)
	if (KERBEROS_CONFIGURED && !quietlog && notickets == 1)
		(void)printf("Warning: no Kerberos tickets issued.\n");
#endif

	if (!quietlog) {
		const char *fname;
#ifdef LOGIN_CAP
		fname = login_getcapstr(lc, "copyright", NULL, NULL);
		if (fname != NULL && access(fname, F_OK) == 0)
			motd(fname);
		else
#endif
			(void)printf("%s", copyrightstr);

#ifdef LOGIN_CAP
		fname = login_getcapstr(lc, "welcome", NULL, NULL);
		if (fname == NULL || access(fname, F_OK) != 0)
#endif
			fname = _PATH_MOTDFILE;
		motd(fname);

		(void)snprintf(tbuf,
		    sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
		if (stat(tbuf, &st) == 0 && st.st_size != 0)
			(void)printf("You have %smail.\n",
			    (st.st_mtime > st.st_atime) ? "new " : "");
	}

#ifdef LOGIN_CAP
	login_close(lc);
#endif

	(void)signal(SIGALRM, SIG_DFL);
	(void)signal(SIGQUIT, SIG_DFL);
	(void)signal(SIGINT, SIG_DFL);
	(void)signal(SIGTSTP, SIG_IGN);

	tbuf[0] = '-';
	(void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
	    p + 1 : pwd->pw_shell, sizeof(tbuf) - 1);

	/* Wait to change password until we're unprivileged */
	if (need_chpass) {
		if (!require_chpass)
			(void)printf(
"Warning: your password has expired. Please change it as soon as possible.\n");
		else {
			int	status;

			(void)printf(
		    "Your password has expired. Please choose a new one.\n");
			switch (fork()) {
			case -1:
				warn("fork");
				sleepexit(EXIT_FAILURE);
			case 0:
				execl(_PATH_BINPASSWD, "passwd", NULL);
				_exit(EXIT_FAILURE);
			default:
				if (wait(&status) == -1 ||
				    WEXITSTATUS(status))
					sleepexit(EXIT_FAILURE);
			}
		}
	}

#ifdef KERBEROS5
	if (login_krb5_get_tickets)
		k5_write_creds();
#endif
	execlp(pwd->pw_shell, tbuf, NULL);
	err(EXIT_FAILURE, "%s", pwd->pw_shell);
}
Esempio n. 15
0
/* Update the localid database, adding when rm is zero, removing otherwise.
 * Documented in detail in poolback.h
 */
int update_localid (struct pulleyback_tlspool *self, der_t *data, int rm) {
	dercursor lid;
	dercursor crd;
	dercursor p11;
	dercursor vex;
	uint32_t flags = 0;
	//
	// Collect DER data for localid and PKCS #11 URI
	lid.derlen =
	p11.derlen =
	vex.derlen = 1030;  // sane upper margin ~1kB
	crd.derlen = 8200;  // sane upper margin ~8kB
	lid.derptr = (uint8_t *) fetch_value (self, MXG_LOCALID, data);
	crd.derptr = (uint8_t *) fetch_value (self, MXG_CRED,    data);
	p11.derptr = (uint8_t *) fetch_value (self, MXG_PKCS11,  data);
	vex.derptr = (uint8_t *) fetch_value (self, MXG_VALEXP,  data);
	assert (lid.derptr != NULL);
	//
	// Enter the DER data to obtain contents and length
	if (crd.derptr == NULL) {
		crd.derlen = 0;
	} else {
		if (der_enter (&crd)) {
			return 0;
		}
	}
	if (der_enter (&lid)) {
		return 0;
	}
	if ((p11.derptr != NULL) && der_enter (&p11)) {
		return 0;
	}
	if ((vex.derptr != NULL) && der_enter (&vex)) {
		return 0;
	}
	//
	// Collect the flags
	if (p11.derptr == NULL) {
		flags |= LID_NO_PKCS11;
	}
	if (check_flag (self, data, MXG_CLIENT, MXG_ROLE)) {
		flags |= LID_ROLE_CLIENT;
	}
	if (check_flag (self, data, MXG_SERVER, MXG_ROLE)) {
		flags |= LID_ROLE_SERVER;
	}
	if (check_flag (self, data, MXG_PEER, MXG_ROLE)) {
		flags |= LID_ROLE_CLIENT | LID_ROLE_SERVER;
	}
	if (check_flag (self, data, MXG_X509, MXG_CREDTYPE)) {
		flags |= LID_TYPE_X509;
	} else if (check_flag (self, data, MXG_PGP, MXG_CREDTYPE)) {
		flags |= LID_TYPE_PGP;
	} else if (vex.derptr != NULL) {
		// Valexp is a case in localid, as an entry LID_TYPE_VALEXP
		flags |= LID_TYPE_VALEXP;
		flags &= ~LID_NO_PKCS11;
	}
	//TODO// MXG_SRP  -> LID_TYPE_SRP
	//TODO// MXG_KRB5 -> LID_TYPE_KRB5
	   else {
		return 0;
	}
	if (check_flag (self, data, MXG_CHAINED, MXG_NONE)) {
		flags |= LID_CHAINED;
	}
	//
	// Handle PKCS #11 URI and/or validation expression
	if (p11.derptr == NULL) {
		// Put the validation expression in the PKCS #11 URI hole
		p11 = vex;
	} else {
		assert (vex.derptr == NULL);
	}
	if (p11.derptr == NULL) {
		p11.derlen = 0;
	}
	//
	// Collect the value for this entry
	dercursor value;
	value.derlen = 4 + p11.derlen + ((p11.derptr != NULL)?1:0) + crd.derlen;
	uint8_t entry [value.derlen];
	value.derptr = entry;
	* (uint32_t *) entry = htonl (flags);
	if (p11.derptr != NULL) {
		memcpy (entry + 4, p11.derptr, p11.derlen);
		entry [4 + p11.derlen] = '\0';
	}
	if (crd.derptr != NULL) {
		memcpy (entry + 4 + p11.derlen + 1, crd.derptr, crd.derlen);
	}
	//
	// Submit the information to the database
	static const uint8_t flag4 [] = { 0x00, 0x00, 0x00, 0xff };
	return update_db (self, &lid, &value, 4, flag4, rm);
}
Esempio n. 16
0
static void server_loop(int fd)
{
	struct timeval snaptime;
	struct pollfd p;
	
	memset(&snaptime, 0, sizeof(snaptime));
	
	p.fd = fd;
	p.events = p.revents = POLLIN;

	load_info();

	for (;;) {
		int status;
		int tdiff;
		struct timeval now;

		gettimeofday(&now, NULL);
		tdiff = T_DIFF(now, snaptime);

//		if (tdiff >= 0) { 
			update_db(tdiff);
			snaptime = now;
			tdiff = 0;
//		}
		if (poll(&p, 1, conf.scan_interval-tdiff) > 0
		    && (p.revents&POLLIN)) {
			int clnt = accept(fd, NULL, NULL);

			if (clnt >= 0) {
				pid_t pid;

				/*
				  We assume forking will be ok
				  so update database here not
				  have races with forked process
				*/

				gettimeofday(&now, NULL);
				tdiff = T_DIFF(now, snaptime);
//				if (tdiff >= min_interval) {
					update_db(tdiff);
					snaptime = now;
					tdiff = 0;
//				}
				poll_client(clnt);
				
				sprintf(info_source,
					"pid=%d sampling_interval=%d "
					"time_const=%d",
					getpid(),
					conf.scan_interval/1000,
					conf.time_constant/1000);

				if (children >= 5) {
					close(clnt);
				} else if ((pid = fork()) != 0) {

					if (pid>0) 
						children++;
					close(clnt);
				} else {
					FILE *fp = fdopen(clnt, "w");
					if (fp) {
						/* Write on clients socket */
						dump_raw_db(fp);
					}
					exit(0);
				}
			}
		}
		while (children && waitpid(-1, &status, WNOHANG) > 0)
			children--;
	}
}
Esempio n. 17
0
void UserData::reconnect()
{
    p->db.open();
    init_buffer();
    update_db();
}
Esempio n. 18
0
File: main.c Progetto: jacques/pkgin
int
main(int argc, char *argv[])
{
	uint8_t		updb_all;
	uint8_t		do_inst = DO_INST; /* by default, do install packages */
	int 		ch, rc = EXIT_SUCCESS;
	struct stat	sb;
	const char	*chrootpath = NULL;

	setprogname(argv[0]);

	if (argc < 2 || *argv[1] == 'h')
		usage();

	while ((ch = getopt(argc, argv, "dhyfFPvVl:nc:t:")) != -1) {
		switch (ch) {
		case 'f':
			force_update = 1;
			break;
		case 'F':
			force_reinstall = 1;
			break;
		case 'y':
			yesflag = 1;
			noflag = 0;
			break;
		case 'n':
			yesflag = 0;
			noflag = 1;
			break;
		case 'v':
			printf("%s %s (using %s)\n", 
				getprogname(), PKGIN_VERSION, pdb_version());
			exit(EXIT_SUCCESS);
			/* NOTREACHED */
		case 'h':
			usage();
			/* NOTREACHED */
		case 'l':
			lslimit = optarg[0];
			break;
		case 'd':
			do_inst = DONT_INST; /* download only */
			break;
		case 'c':
			chrootpath = optarg;
			break;
		case 'V':
			verbosity = 1;
			break;
		case 'P':
			package_version = 1;
			break;
		case 't':
			if ((tracefp = fopen(optarg, "w")) == NULL)
				err(EXIT_FAILURE, MSG_CANT_OPEN_WRITE, optarg);
			break;
		default:
			usage();
			/* NOTREACHED */
		}
	}
	argc -= optind;
	argv += optind;

	if (argc < 1) {
		fprintf(stderr, MSG_MISSING_CMD);
		usage();
		/* NOTREACHED */
	}

	/* initializations */

	/* enter chroot if -c specified */
	if (chrootpath != NULL) {
		if (chroot(chrootpath) == -1)
			errx(-1, MSG_CHROOT_FAILED);

		if (chdir("/") == -1)
			errx(-1, MSG_CHDIR_FAILED);
	}

	/* check for pkg_install */
	if (stat(PKG_ADD, &sb) < 0)
		errx(EXIT_FAILURE, MSG_PKG_INSTALL_NOT_PRESENT);

	/* for pkg_install */
	unsetenv("PKG_PATH");
	/* create base directories */
	if (stat(pkgin_cache, &sb) < 0)
		create_dirs();

	pkgindb_init();

	/* check if current database fits our needs */
	updb_all = upgrade_database();

	/* update local db if pkgdb mtime has changed */
	(void)update_db(LOCAL_SUMMARY, NULL);

	/* split PKG_REPOS env variable and record them */
	split_repos();

	/* 
	 * upgrade remote database if pkgin version changed and not compatible 
	 * or if empty database
	 */
	if (updb_all)
		(void)update_db(REMOTE_SUMMARY, NULL);

	/* find command index */
	ch = find_cmd(argv[0]);

	/* we need packages lists for almost everything */
	if (ch != PKG_UPDT_CMD) /* already loaded by update_db() */
		init_global_pkglists();

	/* fill pkgtools flags */
	if (verbosity)
		strncpy(pkgtools_flags, "-fv", 3);
	else
		strncpy(pkgtools_flags, "-f", 2);

	switch (ch) {
	case PKG_UPDT_CMD: /* update packages db */
		if (update_db(REMOTE_SUMMARY, NULL) == EXIT_FAILURE)
			errx(EXIT_FAILURE, MSG_DONT_HAVE_RIGHTS);
		break;
	case PKG_SHDDP_CMD: /* show direct depends */
		missing_param(argc, 2, MSG_MISSING_PKGNAME);
		rc = show_direct_depends(argv[1]);
		break;
	case PKG_SHFDP_CMD: /* show full dependency tree */
		missing_param(argc, 2, MSG_MISSING_PKGNAME);
		rc = show_full_dep_tree(argv[1],
			DIRECT_DEPS, MSG_FULLDEPTREE);
		break;
	case PKG_SHRDP_CMD: /* show full reverse dependency tree */
		missing_param(argc, 2, MSG_MISSING_PKGNAME);
		rc = show_full_dep_tree(argv[1],
			LOCAL_REVERSE_DEPS,
			MSG_REVDEPTREE);
		break;
	case PKG_LLIST_CMD:
		/* list local packages */
		list_pkgs(LOCAL_PKGS_QUERY_DESC, PKG_LLIST_CMD);
		break;
	case PKG_RLIST_CMD:
		/* list available packages */
		list_pkgs(REMOTE_PKGS_QUERY_DESC, PKG_RLIST_CMD);
		break;
	case PKG_INST_CMD: /* install a package and its dependencies */
		missing_param(argc, 2, MSG_PKG_ARGS_INST);
		pkgin_install(&argv[1], do_inst);
		break;
	case PKG_UPGRD_CMD: /* upgrade keep-packages */
		pkgin_upgrade(UPGRADE_KEEP);
		break;
	case PKG_FUPGRD_CMD: /* upgrade everything installed */
		pkgin_upgrade(UPGRADE_ALL);
		break;
	case PKG_REMV_CMD: /* remove packages and reverse dependencies */
		missing_param(argc, 2, MSG_PKG_ARGS_RM);
		pkgin_remove(&argv[1]);
		break;
	case PKG_AUTORM_CMD: /* autoremove orphan packages */
		pkgin_autoremove();
		break;
	case PKG_KEEP_CMD: /* mark a package as "keep" (not automatic) */
		missing_param(argc, 2, MSG_PKG_ARGS_KEEP);
		pkg_keep(KEEP, &argv[1]);
		break;
	case PKG_UNKEEP_CMD: /* mark a package as "unkeep" (automatic) */
		missing_param(argc, 2, MSG_PKG_ARGS_UNKEEP);
		pkg_keep(UNKEEP, &argv[1]);
		break;
	case PKG_SHKP_CMD: /* show keep packages */
		show_pkg_keep();
		break;
	case PKG_SRCH_CMD: /* search for package */
		missing_param(argc, 2, MSG_MISSING_SRCH);
		search_pkg(argv[1]);
		break;
	case PKG_CLEAN_CMD: /* clean pkgin's packages cache */
		clean_cache();
		break;
	case PKG_EXPORT_CMD: /* export PKGPATH for keep packages */
		export_keep();
		break;
	case PKG_IMPORT_CMD: /* import for keep packages and install them */
		missing_param(argc, 2, MSG_MISSING_FILENAME);
		import_keep(do_inst, argv[1]);
		break;
	case PKG_SHPROV_CMD: /* show what a package provides */
		missing_param(argc, 2, MSG_MISSING_PKGNAME);
		show_prov_req(GET_PROVIDES_QUERY, argv[1]);
		break;
	case PKG_SHREQ_CMD: /* show what a package requires */
		missing_param(argc, 2, MSG_MISSING_PKGNAME);
		show_prov_req(GET_REQUIRES_QUERY, argv[1]);
		break;
	case PKG_SHPKGCONT_CMD: /* show remote package content */
		missing_param(argc, 2, MSG_MISSING_PKGNAME);
		show_pkg_info('L', argv[1]); /* pkg_info flag */
		break;
	case PKG_SHPKGDESC_CMD: /* show remote package DESCR */
		missing_param(argc, 2, MSG_MISSING_PKGNAME);
		show_pkg_info('d', argv[1]); /* pkg_info flag */
		break;
	case PKG_SHPKGBDEFS_CMD: /* show remote package build definitions */
		missing_param(argc, 2, MSG_MISSING_PKGNAME);
		show_pkg_info('B', argv[1]); /* pkg_info flag */
		break;
	case PKG_GINTO_CMD: /* Miod's request */
		ginto();
		break;
	default:
		usage();
		/* NOTREACHED */
	}

	free_global_pkglists();

	pkgindb_close();

	if (tracefp != NULL)
		fclose(tracefp);

	XFREE(env_repos);
	XFREE(pkg_repos);

	return rc;
}
Esempio n. 19
0
/* Update the trust database, adding when rm is zero, removing otherwise.
 * Documented in detail in poolback.h
 */
int update_trust (struct pulleyback_tlspool *self, der_t *data, int rm) {
	dercursor crd;
	dercursor vex;
	uint32_t flags = 0;
	//
	// Collect DER data for validation expression and optional credential
	vex.derlen = 1030;  // sane upper margin ~1kB
	crd.derlen = 8200;  // sane upper margin ~8kB
	crd.derptr = (uint8_t *) fetch_value (self, MXG_CRED,    data);
	vex.derptr = (uint8_t *) fetch_value (self, MXG_VALEXP,  data);
	assert (vex.derptr != NULL);
	//
	// Enter the DER data to obtain contents and length
	if (der_enter (&vex)) {
		return 0;
	}
	if (crd.derptr == NULL) {
		crd.derlen = 0;
	} else {
		if (der_enter (&crd)) {
			return 0;
		}
	}
	//
	// Collect the flags
	if (check_flag (self, data, MXG_CLIENT, MXG_ROLE)) {
		flags |= TAD_ROLE_CLIENT;
	}
	if (check_flag (self, data, MXG_SERVER, MXG_ROLE)) {
		flags |= TAD_ROLE_SERVER;
	}
	if (check_flag (self, data, MXG_PEER, MXG_ROLE)) {
		flags |= TAD_ROLE_CLIENT | TAD_ROLE_SERVER;
	}
	if (check_flag (self, data, MXG_X509, MXG_CREDTYPE)) {
		flags |= TAD_TYPE_X509;
	} else if (check_flag (self, data, MXG_PGP, MXG_CREDTYPE)) {
		flags |= TAD_TYPE_PGP;
	}
	//TODO// MXG_SRP  -> LID_TYPE_SRP
	//TODO// MXG_KRB5 -> LID_TYPE_KRB5
	   else {
		return 0;
	}
	//TODO// if (check_flag (self, data, MXG_NOTROOT, MXG_NONE)) {
	//TODO// 	flags |= TAD_NOTROOT;
	//TODO// }
	//
	// Collect the value for this entry
	dercursor value;
	value.derlen = 4 + vex.derlen + 1 + crd.derlen;
	uint8_t entry [value.derlen];
	value.derptr = entry;
	* (uint32_t *) entry = htonl (flags);
	memcpy (entry + 4, vex.derptr, vex.derlen);
	entry [4 + vex.derlen] = '\0';
	if (crd.derlen > 0) {
		memcpy (entry + 4 + vex.derlen + 1, crd.derptr, crd.derlen);
	}
	//
	//TODO// Determine the key for this entry
	uint8_t keybytes_TODO [] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
	dercursor key;
	key.derptr = keybytes_TODO;
	key.derlen = sizeof (keybytes_TODO);
	//
	// Submit the information to the database
	static const uint8_t flag4 [] = { 0x00, 0x00, 0x00, 0xff };
	return update_db (self, &key, &value, 4, flag4, rm);
}
Esempio n. 20
0
/**
 * Attaches a registry database to the registry object. Prior to calling this,
 * the registry object is not actually connected to the registry. This function
 * attaches it so it can be queried and manipulated.
 *
 * @param [in] reg     the registry to attach to
 * @param [in] path    path to the registry db on disk
 * @param [out] errPtr on error, a description of the error that occurred
 * @return             true if success; false if failure
 */
int reg_attach(reg_registry* reg, const char* path, reg_error* errPtr) {
    struct stat sb;
    int initialized = 1; /* registry already exists */
    int can_write = 1; /* can write to this location */
    int result = 0;
    if (reg->status & reg_attached) {
        reg_throw(errPtr, REG_MISUSE, "a database is already attached to this "
                "registry");
        return 0;
    }
    if (stat(path, &sb) != 0) {
        initialized = 0;
        if (errno == ENOENT) {
            char *dirc, *dname;
            dirc = strdup(path);
            dname = dirname(dirc);
            if (stat(dname, &sb) != 0) {
                can_write = 0;
            }
            free(dirc);
        } else {
            can_write = 0;
        }
    }
    /* can_write is still true if one of the stat calls succeeded */
    if (initialized || can_write) {
        sqlite3_stmt* stmt = NULL;
        char* query = sqlite3_mprintf("ATTACH DATABASE '%q' AS registry", path);
        int r;
        do {
            r = sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL);
        } while (r == SQLITE_BUSY);
        if (r == SQLITE_OK) {
            /* XXX: Busy waiting, consider using sqlite3_busy_handler/timeout */
            do {
                sqlite3_step(stmt);
                r = sqlite3_reset(stmt);
                switch (r) {
                    case SQLITE_OK:
                        if (initialized || (create_tables(reg->db, errPtr))) {
                            Tcl_InitHashTable(&reg->open_entries,
                                    sizeof(sqlite_int64)/sizeof(int));
                            Tcl_InitHashTable(&reg->open_files,
                                    TCL_STRING_KEYS);
                            Tcl_InitHashTable(&reg->open_portgroups,
                                    sizeof(sqlite_int64)/sizeof(int));
                            reg->status |= reg_attached;
                            result = 1;
                        }
                        break;
                    case SQLITE_BUSY:
                        break;
                    default:
                        reg_sqlite_error(reg->db, errPtr, query);
                }
            } while (r == SQLITE_BUSY);

            sqlite3_finalize(stmt);
            stmt = NULL;

            if (result) {
                result &= update_db(reg->db, errPtr);
            }
        } else {
            reg_sqlite_error(reg->db, errPtr, query);
        }
        if (stmt) {
            sqlite3_finalize(stmt);
        }
        sqlite3_free(query);
    } else {
        reg_throw(errPtr, REG_CANNOT_INIT, "port registry doesn't exist at "
                "\"%q\" and couldn't write to this location", path);
    }
    return result;
}