Exemplo n.º 1
0
/*
 * Write accounting data to syslog
 */
int
do_acct_syslog(struct acct_rec *rec)
{
    char *acct_type;
    char *cmdbuf;
    int written, i;
    size_t bufsize;

    bufsize = 1024;

    cmdbuf = tac_malloc(bufsize);
    memset(cmdbuf, 0, bufsize);
    written = 0;

    switch(rec->acct_type) {
	case ACCT_TYPE_UPDATE:
	    acct_type = "update";
	    break;
	case ACCT_TYPE_START:
	    acct_type = "start";
	    break;
	case ACCT_TYPE_STOP:
	    acct_type = "stop";
	    break;
	default:
	    acct_type = "default";
    }

    for (i = 0; i < rec->num_args; i++) {
	/* possible 4 spaces and and a null terminator == 5 */
	if ((strlen(rec->args[i]) + written + 5) > bufsize) {
	    cmdbuf = tac_realloc(cmdbuf, strlen(rec->args[i]) + written + 5);
	    bufsize += strlen(rec->args[i]) + written + 5;
	}

	strncat(cmdbuf, rec->args[i], strlen(rec->args[i]));
	written += strlen(rec->args[i]);

	if (i < (rec->num_args - 1)) {
	    strncat(cmdbuf, "    ", 4);
	    written += 4;
	}
    }

    syslog(LOG_INFO, "%s    %s    %s    %s    %s    %s",
	   ((rec->identity->NAS_name) && rec->identity->NAS_name[0]) ?
	    rec->identity->NAS_name : "unknown",
	   ((rec->identity->username) && rec->identity->username[0]) ?
	    rec->identity->username : "******",
	   ((rec->identity->NAS_port) && rec->identity->NAS_port[0]) ?
	    rec->identity->NAS_port : "unknown",
	   ((rec->identity->NAC_address) && rec->identity->NAC_address[0]) ?
	    rec->identity->NAC_address : "unknown",
	   acct_type, cmdbuf);

    free(cmdbuf);

    return 0;
}
Exemplo n.º 2
0
/* send an accounting response packet */
void
send_acct_reply(u_char status, char *msg, char *data)
{
    u_char *pak, *p;
    HDR *hdr;
    int len;
    struct acct_reply *reply;
    int msg_len, data_len;

    msg_len = msg ? strlen(msg) : 0;
    data_len = data ? strlen(data) : 0;

    len = TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE + msg_len +
	  data_len;

    pak = (u_char *)tac_malloc(len);
    reply = (struct acct_reply *)(pak + TAC_PLUS_HDR_SIZE);
    hdr = (HDR *)pak;

    memset(pak, 0, len);

    hdr->version = TAC_PLUS_VER_0;
    hdr->type = TAC_PLUS_ACCT;
    hdr->seq_no = ++session.seq_no;
    hdr->flags = TAC_PLUS_UNENCRYPTED;
    if (!(session.flags & SESS_NO_SINGLECONN))
	hdr->flags |= (session.peerflags & TAC_PLUS_SINGLE_CONNECT_FLAG);
    hdr->session_id = htonl(session.session_id);
    hdr->datalength = htonl(len - TAC_PLUS_HDR_SIZE);

    reply->status = status;
    reply->msg_len  = msg_len;
    reply->data_len = data_len;

    p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE;
    memcpy(p, msg, msg_len);
    p += msg_len;

    memcpy(p, data, data_len);

    if (debug & DEBUG_PACKET_FLAG) {
	report(LOG_DEBUG, "Writing %s size=%d",
	       summarise_outgoing_packet_type(pak), len);
	dump_tacacs_pak(pak);
    }

    reply->msg_len = ntohs(reply->msg_len);
    reply->data_len = ntohs(reply->data_len);

    write_packet(pak);
    free(pak);

    return;
}
Exemplo n.º 3
0
static void
declare(char *name, int value)
{
    KEYWORD *n;
    KEYWORD *k = (KEYWORD *)tac_malloc(sizeof(KEYWORD));

    k->word = tac_strdup(name);
    k->value = value;

    n = hash_add_entry(wordtable, (void *) k);

    if (n) {
	report(LOG_ERR, "Attempt to multiply define keyword %s", name);
	tac_exit(1);
    }
}
Exemplo n.º 4
0
char *
tac_realloc(char *ptr, int size)
{
    char *p;

    if (ptr == NULL) {
	/* realloc(0, size) is not portable */
	p = tac_malloc(size);
    } else {
	p = (char *)realloc(ptr, size);
    }

    if (p == NULL) {
	report(LOG_ERR, "realloc %d failure", size);
	tac_exit(1);
    }
    return(p);
}
Exemplo n.º 5
0
/*
 * Reassemble the command arguments as typed by the user, out of the
 * array of args we received. Return "" if there are no arguments.
 */
static char *
assemble_args(struct author_data *data)
{
    char *buf;
    int i;
    char *nas_arg, *v;
    int len;

    len = 0;
    for (i = 0; i < data->num_in_args; i++) {
	nas_arg = data->input_args[i];
	if (strncmp(nas_arg, "cmd-arg", strlen("cmd-arg")) == 0) {
	    v = value(nas_arg);
	    if (v != NULL)
		len += strlen(v) + 1;
	}
    }

    if (len <= 0) {
	return(tac_strdup(""));
    }

    buf = tac_malloc(len);
    buf[0] = '\0';

    for (i = 0; i < data->num_in_args; i++) {
	nas_arg = data->input_args[i];
	if (strncmp(nas_arg, "cmd-arg", strlen("cmd-arg")))
	    continue;

	v = value(nas_arg);
	if (!v) {
	    free(buf);
	    return(NULL);
	}
	strncat(buf, v, len - 1);
	len -= strlen(v);
	if (i < (data->num_in_args - 1)) {
	    strncat(buf, " ", len - 1);
	    len -= 1;
	}
    }
    return(buf);
}
Exemplo n.º 6
0
char *
tac_make_string(u_char *p, int len)
{
    char *string;
    int new_len = len;

    /*
     * Add space for a null terminator if needed. Also, no telling
     * what various mallocs will do when asked for a length of zero.
     */
    if (len == 0 || p[len - 1])
	new_len++;

    string = (char *)tac_malloc(new_len);

    memset(string, 0, new_len);
    memcpy(string, p, len);
    return(string);
}
Exemplo n.º 7
0
/*
 * Return 0 means data->status is valid.
 * protocol is only valid if svc == ppp.
 */
static int
authorize_svc(char *user, int svc, char *protocol, char *svcname,
	      struct author_data *data)
{
    int max_args;
    char **out_args, **outp;
    char *nas_arg, *cfg_arg;
    int i, j;
    char **cfg_args;
    char **cfg_argp;
    int deny_by_default;
    NODE *node;

    int replaced = 0;
    int added = 0;
    int cfg_cnt;

    /* Does this service exist? */
    node = cfg_get_svc_node(user, svc, protocol, svcname, TAC_PLUS_RECURSE);

    if (!node) {
	/* Service not found. If the default is permit, or this is an
	 * PPP/LCP request and other ppp services are configured,
	 * we'll allow it. */

	if (cfg_user_svc_default_is_permit(user)) {
	    if (debug & DEBUG_AUTHOR_FLAG)
		report(LOG_DEBUG, "svc=%s protocol=%s svcname=%s not found, "
		       "permitted by default", cfg_nodestring(svc),
		       protocol ? protocol : "", svcname ? svcname : "");

	    data->status = AUTHOR_STATUS_PASS_ADD;
	    data->num_out_args = 0;
	    data->output_args = NULL;
	    return(0);
	}

	if (ppp_lcp_allowed(svc, protocol, user)) {
	    data->status = AUTHOR_STATUS_PASS_ADD;
	    data->num_out_args = 0;
	    data->output_args = NULL;
	    return(0);
	}

	if (debug & DEBUG_AUTHOR_FLAG)
	    report(LOG_DEBUG, "svc=%s protocol=%s not found, denied by default",
		   cfg_nodestring(svc), protocol ? protocol : "");

	data->status = AUTHOR_STATUS_FAIL;
	data->num_out_args = 0;
	data->output_args = NULL;
	return(0);
    }

    /* Get server args configured in the config file. */
    cfg_args = cfg_get_svc_attrs(node, &deny_by_default);

    /* Check the nas args for well-formedness */
    for (i = 0; i < data->num_in_args; i++) {
	if (!arg_ok(data->input_args[i])) {
	    char buf[MAX_INPUT_LINE_LEN+50];
	    snprintf(buf, sizeof(buf), "Illegal arg %s from NAS",
		     data->input_args[i]);
	    data->status = AUTHOR_STATUS_ERROR;
	    data->admin_msg = tac_strdup(buf);
	    report(LOG_ERR, "%s: Error %s", session.peer, buf);

	    /* free any server arguments */
	    for (cfg_argp = cfg_args; cfg_args && *cfg_argp; cfg_argp++)
		free(*cfg_argp);
	    free(cfg_args);
	    return(0);
	}
    }

    /* How many configured AV pairs are there ? */
    for (cfg_cnt = 0; cfg_args && cfg_args[cfg_cnt];)
	cfg_cnt++;

    /* Allocate space for in + out args */
    max_args = cfg_cnt + data->num_in_args;
    out_args = (char **)tac_malloc((max_args + 1) * sizeof(char *));
    outp = out_args;
    data->num_out_args = 0;

    memset(out_args, 0, (max_args + 1) * sizeof(char *));

    for (i = 0; i < data->num_in_args; i++) {
	nas_arg = data->input_args[i];

	/* always pass these pairs through unchanged */
	if (match_attrs(nas_arg, "service=") ||
	    match_attrs(nas_arg, "protocol=") ||
	    match_attrs(nas_arg, "cmd=")) {

	    if (debug & DEBUG_AUTHOR_FLAG) {
		report(LOG_DEBUG, "nas:%s (passed thru)", nas_arg);
	    }
	    *outp++ = tac_strdup(nas_arg);
	    data->num_out_args++;
	    continue;
	}

	/* NAS AV pair is mandatory */
	if (mandatory(nas_arg)) {
	    /*
	     * a). look for an exact attribute,value match in the daemon's
	     * mandatory list. If found, add the AV pair to the output
	     */
	    for (j = 0; j < cfg_cnt; j++) {
		cfg_arg = cfg_args[j];
		if (optional(cfg_arg))
		    continue;

		if (STREQ(nas_arg, cfg_arg)) {
		    if (debug & DEBUG_AUTHOR_FLAG) {
			report(LOG_DEBUG, "nas:%s, svr:%s -> add %s (a)",
			       nas_arg, cfg_arg, nas_arg);
		    }
		    *outp++ = tac_strdup(nas_arg);
		    data->num_out_args++;
		    goto next_nas_arg;
		}
	    }

	    /*
	     * b). If an exact match doesn't exist, look in the daemon's
	     * optional list for the first attribute match. If found, add the
	     * NAS AV pair to the output
	     */
	    for (j = 0; j < cfg_cnt; j++) {
		cfg_arg = cfg_args[j];
		if (mandatory(cfg_arg))
		    continue;

		if (match_attrs(nas_arg, cfg_arg)) {
		    if (debug & DEBUG_AUTHOR_FLAG) {
			report(LOG_DEBUG, "nas:%s, svr:%s -> add %s (b)",
			       nas_arg, cfg_arg, nas_arg);
		    }
		    *outp++ = tac_strdup(nas_arg);
		    data->num_out_args++;
		    goto next_nas_arg;
		}
	    }

	    /*
	     * c). If no attribute match exists, deny the command if the
	     * default is to deny
	     */
	    if (deny_by_default) {
		data->status = AUTHOR_STATUS_FAIL;
		if (debug & DEBUG_AUTHOR_FLAG) {
		    report(LOG_DEBUG, "nas:%s svr:absent, default=deny -> "
							"denied (c)", nas_arg);
		}
		if (out_args) {
		    for (i = 0; i < data->num_out_args; i++)
			free(out_args[i]);
		    free(out_args);
		}

		data->num_out_args = 0;
		data->output_args = NULL;

		/* free the server arguments */
		for (cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
		    free(*cfg_argp);
		free(cfg_args);
		return(0);
	    }

	    /*
	     * d). If the default is permit, add the NAS AV pair to the output
	     */
	    if (debug & DEBUG_AUTHOR_FLAG) {
		report(LOG_DEBUG,
		       "nas:%s, svr:absent, default=permit -> add %s (d)",
		       nas_arg, nas_arg);
	    }
	    *outp++ = tac_strdup(nas_arg);
	    data->num_out_args++;
	    goto next_nas_arg;
	} else {
	    /*
	     * NAS AV pair is Optional
	     *
	     * e). look for an exact attribute,value match in the mandatory
	     * list. If found, add DAEMON's AV pair to output
	     */
	    for (j = 0; j < cfg_cnt; j++) {
		cfg_arg = cfg_args[j];
		if (optional(cfg_arg))
		    continue;

		if (match_attrs(nas_arg, cfg_arg) &&
		    match_values(nas_arg, cfg_arg)) {

		    if (debug & DEBUG_AUTHOR_FLAG) {
			report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s "
					"(e)", nas_arg, cfg_arg, cfg_arg);
		    }
		    *outp++ = tac_strdup(cfg_arg);
		    data->num_out_args++;
		    replaced++;
		    goto next_nas_arg;
		}
	    }

	    /*
	     * f). If not found, look for the first attribute match in the
	     * mandatory list. If found, add DAEMONS's AV pair to output
	     */
	    for (j = 0; j < cfg_cnt; j++) {
		cfg_arg = cfg_args[j];
		if (optional(cfg_arg))
		    continue;

		if (match_attrs(nas_arg, cfg_arg)) {
		    if (debug & DEBUG_AUTHOR_FLAG) {
			report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s "
					"(f)", nas_arg, cfg_arg, cfg_arg);
		    }
		    *outp++ = tac_strdup(cfg_arg);
		    data->num_out_args++;
		    replaced++;
		    goto next_nas_arg;
		}
	    }

	    /*
	     * g). If no mandatory match exists, look for an exact
	     * attribute,value pair match among the daemon's optional AV
	     * pairs. If found add the DAEMON's matching AV pair to the
	     * output.
	     */
	    for (j = 0; j < cfg_cnt; j++) {
		cfg_arg = cfg_args[j];
		if (!optional(cfg_arg))
		    continue;

		if (match_attrs(nas_arg, cfg_arg) &&
		    match_values(nas_arg, cfg_arg)) {
		    if (debug & DEBUG_AUTHOR_FLAG) {
			report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s "
					"(g)", nas_arg, cfg_arg, cfg_arg);
		    }
		    *outp++ = tac_strdup(cfg_arg);
		    data->num_out_args++;
		    replaced++;
		    goto next_nas_arg;
		}
	    }

	    /*
	     * h). If no exact match exists, locate the first attribute match
	     * among the daemon's optional AV pairs. If found add the DAEMON's
	     * matching AV pair to the output
	     */
	    for (j = 0; j < cfg_cnt; j++) {
		cfg_arg = cfg_args[j];
		if (!optional(cfg_arg))
		    continue;

		if (match_attrs(nas_arg, cfg_arg)) {
		    if (debug & DEBUG_AUTHOR_FLAG) {
			report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s "
			       "(h)", nas_arg, cfg_arg, cfg_arg);
		    }
		    *outp++ = tac_strdup(cfg_arg);
		    data->num_out_args++;
		    replaced++;
		    goto next_nas_arg;
		}
	    }

	    /*
	     * i). If no match is found, delete the AV pair if default is deny
	     */
	    if (deny_by_default) {
		if (debug & DEBUG_AUTHOR_FLAG) {
		    report(LOG_DEBUG, "nas:%s svr:absent/deny -> delete %s (i)",
			   nas_arg, nas_arg);
		}
		replaced++;
		goto next_nas_arg;
	    }

	    /* j). If the default is permit add the NAS AV pair to the output */
	    if (debug & DEBUG_AUTHOR_FLAG) {
		report(LOG_DEBUG, "nas:%s svr:absent/permit -> add %s (j)",
		       nas_arg, nas_arg);
	    }
	    *outp++ = tac_strdup(nas_arg);
	    data->num_out_args++;
	    goto next_nas_arg;
	}
    next_nas_arg:;
    }

    /*
     * k). After all AV pairs have been processed, for each mandatory DAEMON
     * AV pair, if there is no attribute match already in the output list, add
     * the AV pair (add only one AV pair for each mandatory attribute)
     */
    for (i = 0; i < cfg_cnt; i++) {
	cfg_arg = cfg_args[i];

	if (!mandatory(cfg_arg))
	    continue;

	for (j = 0; j < data->num_out_args; j++) {
	    char *output_arg = out_args[j];

	    if (match_attrs(cfg_arg, output_arg)) {
		goto next_cfg_arg;
	    }
	}

	/* Attr is required by daemon but not present in output. Add it */
	if (debug & DEBUG_AUTHOR_FLAG) {
	    report(LOG_DEBUG, "nas:absent, server:%s -> add %s (k)",
		   cfg_arg, cfg_arg);
	}
	added++;
	*outp++ = tac_strdup(cfg_arg);
	data->num_out_args++;

    next_cfg_arg:
	;
    }

    /*
     * If we replaced or deleted some pairs we must return the entire list we
     * have constructed
     */
    if (replaced) {
	if (debug & DEBUG_AUTHOR_FLAG) {
	    report(LOG_DEBUG, "replaced %d args", replaced);
	}
	data->status = AUTHOR_STATUS_PASS_REPL;
	data->output_args = out_args;

	/* free the server arguments */
	for (cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
	    free(*cfg_argp);
	free(cfg_args);

	return(0);
    }

    /*
     * We added something not on the original nas list, but did not replace or
     * delete anything. We should return only the additions
     */
    if (added) {
	if (debug & DEBUG_AUTHOR_FLAG)
	    report(LOG_DEBUG, "added %d args", added);

	/* throw away output args which are just copies of the input args */
	for (i = 0; i < data->num_in_args; i++) {
	    if (debug & DEBUG_AUTHOR_FLAG) {
		report(LOG_DEBUG, "out_args[%d] = %s input copy discarded",
		       i, out_args[i]);
	    }
	    free(out_args[i]);
	    out_args[i] = NULL;
	}

	/*
	 * Now compact the new args added to the end of the array down to the
	 * beginning
	 */
	j = 0;
	for (i = data->num_in_args; i < data->num_out_args; i++) {
	    if (out_args[j]) /* we goofed */
		report(LOG_ERR, "%s: out_args[%d] should be NULL",
		       session.peer, j);
	    if (!out_args[i]) /* we goofed */
		report(LOG_ERR, "%s: out_args[%d] should not be NULL",
		       session.peer, i);

	    if (debug & DEBUG_AUTHOR_FLAG) {
		report(LOG_DEBUG, "out_args[%d] = %s compacted to out_args[%d]",
		       i, out_args[i], j);
	    }
	    out_args[j++] = out_args[i];
	    out_args[i] = NULL;
	}
	data->num_out_args = j;
	if (debug & DEBUG_AUTHOR_FLAG) {
	    report(LOG_DEBUG, "%d output args", data->num_out_args);
	}

	/* should/could do a realloc here but it won't matter */
	data->status = AUTHOR_STATUS_PASS_ADD;
	data->output_args = out_args;

	/* free the server arguments */
	for (cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
	    free(*cfg_argp);
	free(cfg_args);

	return(0);
    }

    /*
     * no additions or replacements. Input and output are identical. Don't
     * need to return anything
     */
    if (debug & DEBUG_AUTHOR_FLAG) {
	report(LOG_DEBUG, "added %d", added);
    }
    data->status = AUTHOR_STATUS_PASS_ADD;
    if (out_args) {
	for (i = 0; i < data->num_out_args; i++) {
	    free(out_args[i]);
	}
	free(out_args);
    }

    /* Final sanity check */
    if (data->num_out_args != data->num_in_args) {
	data->status = AUTHOR_STATUS_ERROR;
	data->admin_msg = tac_strdup("Bad output arg cnt from do_author");
	report(LOG_ERR, "%s: Error %s", session.peer, data->admin_msg);

	/* free the server arguments */
	for (cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
	    free(*cfg_argp);
	free(cfg_args);

	return(0);
    }

    data->num_out_args = 0;
    data->output_args = NULL;

    /* free the server arguments */
    for (cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
	free(*cfg_argp);
    free(cfg_args);

    return(0);
}
Exemplo n.º 8
0
static void
account(u_char *pak)
{
    struct acct *acct_pak;
    u_char *p, *argsizep;
    struct acct_rec rec;
    struct identity identity;
    char **cmd_argp;
    int i, errors = 0, status;

    acct_pak = (struct acct *) (pak + TAC_PLUS_HDR_SIZE);

    /* Fill out accounting record structure */
    memset(&rec, 0, sizeof(struct acct_rec));

    if (acct_pak->flags & TAC_PLUS_ACCT_FLAG_WATCHDOG)
	rec.acct_type = ACCT_TYPE_UPDATE;
    if (acct_pak->flags & TAC_PLUS_ACCT_FLAG_START)
	rec.acct_type = ACCT_TYPE_START;
    if (acct_pak->flags & TAC_PLUS_ACCT_FLAG_STOP)
	rec.acct_type = ACCT_TYPE_STOP;

    rec.authen_method  = acct_pak->authen_method;
    rec.authen_type    = acct_pak->authen_type;
    rec.authen_service = acct_pak->authen_service;

    /* start of variable length data is here */
    p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REQ_FIXED_FIELDS_SIZE;

    /* skip arg cnts */
    p += acct_pak->arg_cnt;

    /* zero out identity struct */
    memset(&identity, 0, sizeof(struct identity));

    identity.username = tac_make_string(p, (int)acct_pak->user_len);
    p += acct_pak->user_len;

    identity.NAS_name = tac_strdup(session.peer);

    identity.NAS_port = tac_make_string(p, (int)acct_pak->port_len);
    p += acct_pak->port_len;
    if (acct_pak->port_len <= 0) {
	strcpy(session.port, "unknown-port");
    } else {
	strcpy(session.port, identity.NAS_port);
    }

    identity.NAC_address = tac_make_string(p, (int)acct_pak->rem_addr_len);
    p += acct_pak->rem_addr_len;

    identity.priv_lvl = acct_pak->priv_lvl;

    rec.identity = &identity;

    /* Now process cmd args */
    argsizep = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REQ_FIXED_FIELDS_SIZE;

    cmd_argp = (char **)tac_malloc(acct_pak->arg_cnt * sizeof(char *));

    for (i = 0; i < (int)acct_pak->arg_cnt; i++) {
	cmd_argp[i] = tac_make_string(p, *argsizep);
	p += *argsizep++;
    }

    rec.args = cmd_argp;
    rec.num_args = acct_pak->arg_cnt;

#ifdef MAXSESS
    /* Tally for MAXSESS counting */
    loguser(&rec);
#endif

    /* Do accounting */
    if (wtmpfile)
	errors = do_wtmp(&rec);
    if (session.acctfile != NULL)
	errors += do_acct_file(&rec);
    if (session.flags & SESS_FLAG_ACCTSYSL)
	errors += do_acct_syslog(&rec);

    if (errors) {
	status = TAC_PLUS_ACCT_STATUS_ERROR;
    } else {
	status = TAC_PLUS_ACCT_STATUS_SUCCESS;
    }
    send_acct_reply(status, rec.msg, rec.admin_msg);

    free(identity.username);
    free(identity.NAS_name);
    free(identity.NAS_port);
    free(identity.NAC_address);

    for (i = 0; i < (int)acct_pak->arg_cnt; i++) {
	free(cmd_argp[i]);
    }
    free(cmd_argp);

    if (rec.msg)
	free(rec.msg);
    if (rec.admin_msg)
	free(rec.admin_msg);
}
Exemplo n.º 9
0
/*
 * read a packet from the wire, and decrypt it.  Increment the global
 * seq_no return NULL on failure
 */
u_char *
read_packet(void)
{
    HDR		hdr;
    u_char	*pkt, *data;
    int		len;
    char	*tkey;

    if (debug & DEBUG_PACKET_FLAG)
	report(LOG_DEBUG, "Waiting for packet");

    /* read a packet header */
    len = sockread(session.sock, (u_char *)&hdr,
		   TAC_PLUS_HDR_SIZE, cfg_get_readtimeout());
    if (len != TAC_PLUS_HDR_SIZE) {
	report(LOG_DEBUG, "Read %d bytes from %s %s, expecting %d",
	       len, session.peer, session.port, TAC_PLUS_HDR_SIZE);
	return(NULL);
    }
    session.peerflags = hdr.flags;

    if ((hdr.version & TAC_PLUS_MAJOR_VER_MASK) != TAC_PLUS_MAJOR_VER) {
	report(LOG_ERR, "%s: Illegal major version specified: found %d wanted "
	       "%d\n", session.peer, hdr.version, TAC_PLUS_MAJOR_VER);
	return(NULL);
    }

    /* get memory for the packet */
    len = TAC_PLUS_HDR_SIZE + ntohl(hdr.datalength);
    if ((ntohl(hdr.datalength) & ~0xffffUL) ||
	(len < TAC_PLUS_HDR_SIZE) || (len > 0x10000)) {
	report(LOG_ERR, "%s: Illegal data size: %lu\n", session.peer,
	       ntohl(hdr.datalength));
	return(NULL);
    }
    pkt = (u_char *)tac_malloc(len);

    /* initialise the packet */
    memcpy(pkt, &hdr, TAC_PLUS_HDR_SIZE);

    /* the data start here */
    data = pkt + TAC_PLUS_HDR_SIZE;

    /* read the rest of the packet data */
    if (sockread(session.sock, data, ntohl(hdr.datalength),
		 cfg_get_readtimeout()) != ntohl(hdr.datalength)) {
	report(LOG_ERR, "%s: start_session: bad socket read", session.peer);
	free(pkt);
	return(NULL);
    }
    session.seq_no++;		/* should now equal that of incoming packet */
    session.last_exch = time(NULL);

    if (session.seq_no != hdr.seq_no) {
	report(LOG_ERR, "%s: Illegal session seq # %d != packet seq # %d",
	       session.peer, session.seq_no, hdr.seq_no);
	free(pkt);
	return(NULL);
    }

    /* decrypt the data portion */
    tkey = cfg_get_host_key(session.peerip);
    if (tkey == NULL && !STREQ(session.peer, session.peerip)) {
	tkey = cfg_get_host_prompt(session.peer);
    }
    if (tkey == NULL)
	tkey = session.key;
    if (md5_xor((HDR *)pkt, data, tkey)) {
	report(LOG_ERR, "%s: start_session error decrypting data",
	       session.peer);
	free(pkt);
	return(NULL);
    }

    if (debug & DEBUG_PACKET_FLAG)
	report(LOG_DEBUG, "Read %s size=%d",
	       summarise_incoming_packet_type(pkt), len);

    session.version = hdr.version;

    return(pkt);
}
Exemplo n.º 10
0
/* send an authorization reply packet */
void
send_author_reply(u_char status, char *msg, char *data, int arg_cnt,
		  char **args)
{
    u_char *pak, *p;
    HDR *hdr;
    struct author_reply *reply;
    int msg_len;
    int len;
    int data_len;
    int i;

    data_len = (data ? strlen(data) : 0);
    msg_len  = (msg  ? strlen(msg)  : 0);

    /* start calculating final packet size */
    len = TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE + msg_len +
	  data_len;

    for (i = 0; i < arg_cnt; i++) {
	/* space for the arg and its length */
	len += strlen(args[i]) + 1;
    }

    pak = (u_char *)tac_malloc(len);

    memset(pak, 0, len);

    hdr = (HDR *)pak;

    reply = (struct author_reply *) (pak + TAC_PLUS_HDR_SIZE);

    hdr->version = TAC_PLUS_VER_0;
    hdr->type = TAC_PLUS_AUTHOR;
    hdr->seq_no = ++session.seq_no;
    hdr->flags = TAC_PLUS_UNENCRYPTED;
    if (!(session.flags & SESS_NO_SINGLECONN))
	hdr->flags |= (session.peerflags & TAC_PLUS_SINGLE_CONNECT_FLAG);
    hdr->session_id = htonl(session.session_id);
    hdr->datalength = htonl(len - TAC_PLUS_HDR_SIZE);

    reply->status   = status;
    reply->msg_len  = msg_len;
    reply->data_len = data_len;
    reply->arg_cnt  = arg_cnt;

    p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE;

    /* place arg sizes into packet  */
    for (i = 0; i < arg_cnt; i++) {
	*p++ = strlen(args[i]);
    }

    memcpy(p, msg, msg_len);
    p += msg_len;

    memcpy(p, data, data_len);
    p += data_len;

    /* copy arg bodies into packet */
    for (i = 0; i < arg_cnt; i++) {
	int arglen = strlen(args[i]);

	memcpy(p, args[i], arglen);
	p += arglen;
    }

    if (debug & DEBUG_PACKET_FLAG) {
	report(LOG_DEBUG, "Writing %s size=%d",
	       summarise_outgoing_packet_type(pak), len);
	dump_tacacs_pak(pak);
    }

    reply->msg_len  = htons(reply->msg_len);
    reply->data_len = htons(reply->data_len);

    write_packet(pak);
    free(pak);

    return;
}
Exemplo n.º 11
0
/*
 *  Come here when we receive an authorization START packet
 */
void
author(u_char *pak)
{
    HDR *hdr;
    struct author *apak;
    struct identity identity;
#ifdef ACLS
    struct authen_data authen_data;
#endif
    struct author_data author_data;
    u_char *p;
    u_char *argsizep;
    char **cmd_argp;
    int i, len;

    if (debug & DEBUG_AUTHOR_FLAG)
	report(LOG_DEBUG, "Start authorization request");

    hdr = (HDR *)pak;
    apak = (struct author *)(pak + TAC_PLUS_HDR_SIZE);

    /* Do some sanity checks */
    if (hdr->seq_no != 1) {
	send_error_reply(TAC_PLUS_AUTHOR, NULL);
	return;
    }

    /* Check if there's at least sizeof(struct author) of useful data */
    if (ntohl(hdr->datalength) < TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE) {
	report(LOG_ERR, "%s: author minimum payload length: %zu, got: %u",
	       session.peer, TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE,
	       ntohl(hdr->datalength));
	send_error_reply(TAC_PLUS_AUTHOR, NULL);
	return;
    }

    /* arg counts start here */
    p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE;

    /* Length checks */
    len = TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE;
    len += apak->user_len + apak->port_len + apak->rem_addr_len + apak->arg_cnt;

    /* Is there enough space for apak->arg_cnt arguments? */
    if (ntohl(hdr->datalength) <
	(TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE + apak->arg_cnt)) {
	report(LOG_ERR, "%s: author minimum payload length: %zu, got: %u",
	       session.peer, TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE + apak->arg_cnt,
	       ntohl(hdr->datalength));
	send_error_reply(TAC_PLUS_AUTHOR, NULL);
	return;
    }

    for (i = 0; i < (int)apak->arg_cnt; i++) {
	len += p[i];
    }

    if (len != ntohl(hdr->datalength)) {
	send_error_reply(TAC_PLUS_AUTHOR, NULL);
	return;
    }

    /* start of variable length data is here */
    p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE;

    /* arg length data starts here */
    argsizep = p;

    p += apak->arg_cnt;

    memset(&author_data, 0, sizeof(struct author_data));

    /* The identity structure */

    /* zero out identity struct */
    memset(&identity, 0, sizeof(struct identity));
    identity.username = tac_make_string(p, (int)apak->user_len);
    p += apak->user_len;

    identity.NAS_name = tac_strdup(session.peer);
#ifdef ACLS
    identity.NAS_ip = tac_strdup(session.peerip);
#endif

    identity.NAS_port = tac_make_string(p, (int)apak->port_len);
    p += apak->port_len;
    if (apak->port_len <= 0) {
	strcpy(session.port, "unknown-port");
    } else {
	strcpy(session.port, identity.NAS_port);
    }

    identity.NAC_address = tac_make_string(p, (int)apak->rem_addr_len);
    p += apak->rem_addr_len;

    identity.priv_lvl = apak->priv_lvl;

    /* The author_data structure */

    author_data.id = &identity;	/* user id */

    /* FIXME: validate these fields */
    author_data.authen_method = apak->authen_method;
    author_data.authen_type = apak->authen_type;
    author_data.service = apak->service;
    author_data.num_in_args = apak->arg_cnt;

    /* Space for args + NULL */
    cmd_argp = (char **)tac_malloc(apak->arg_cnt * sizeof(char *));

    /* p points to the start of args. Step thru them making strings */
    for (i = 0; i < (int)apak->arg_cnt; i++) {
	cmd_argp[i] = tac_make_string(p, *argsizep);
	p += *argsizep++;
    }

    author_data.input_args = cmd_argp;	/* input command arguments */

#ifdef ACLS
    authen_data.NAS_id = &identity;
    if (verify_host(author_data.id->username, &authen_data, S_acl,
		    TAC_PLUS_RECURSE) != S_permit) {
	author_data.status = AUTHOR_STATUS_FAIL;
    } else
#endif
	if (do_author(&author_data)) {
	    report(LOG_ERR, "%s: do_author returned an error", session.peer);
	    send_author_reply(AUTHOR_STATUS_ERROR,
			      author_data.msg, author_data.admin_msg,
			      author_data.num_out_args,
			      author_data.output_args);
	    return;
        }

    /* Send a reply packet */
    send_author_reply(author_data.status, author_data.msg,
		      author_data.admin_msg, author_data.num_out_args,
		      author_data.output_args);

    if (debug)
	report(LOG_INFO, "authorization query for '%s' %s from %s %s",
	       author_data.id->username && author_data.id->username[0] ?
	       author_data.id->username : "******",
	       author_data.id->NAS_port && author_data.id->NAS_port[0] ?
	       author_data.id->NAS_port : "unknown",
	       session.peer,
	       (author_data.status == AUTHOR_STATUS_PASS_ADD ||
		author_data.status == AUTHOR_STATUS_PASS_REPL) ?
	       "accepted" : "rejected");

    /* free the input args */
    if (author_data.input_args) {
	for (i = 0; i < author_data.num_in_args; i++)
	    free(author_data.input_args[i]);

	free(author_data.input_args);
	author_data.input_args = NULL;
    }

    /* free the output args */
    if (author_data.output_args) {
	for (i = 0; i < author_data.num_out_args; i++)
	    free(author_data.output_args[i]);

	free(author_data.output_args);
	author_data.output_args = NULL;
    }

    if (author_data.msg)
	free(author_data.msg);

    if (author_data.admin_msg)
	free(author_data.admin_msg);

    free(identity.username);
    free(identity.NAS_name);
#ifdef ACLS
    free(identity.NAS_ip);
#endif
    free(identity.NAS_port);
    free(identity.NAC_address);
}