Date: Sun, 5 Aug 2007 18:59:25 GMT From: Fredrik Lindberg <fli@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 124747 for review Message-ID: <200708051859.l75IxPJj044037@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=124747 Change 124747 by fli@fli_nexus on 2007/08/05 18:58:30 - Add support to manipulate the record database. Allows add, remove and list operations (root only). - Add support to view and flush the cache (root only). - Add support to view active interfaces (root only). - Follow name change (mdnsd_clipkg.h -> mdnsd_ipc.h). - Save client credentials aquired from socket. - Change how messages are read. Read for as long as data is available, also use length information encoded in message to properly separate messages. Affected files ... .. //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.c#2 edit .. //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.h#2 edit Differences ... ==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.c#2 (text+ko) ==== @@ -34,13 +34,14 @@ #include <errno.h> #include <fcntl.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> #include "event.h" #include "clisrv.h" #include "mdnsd.h" -#include "mdnsd_clipkg.h" +#include "mdnsd_ipc.h" #include "log.h" #include "objalloc.h" #include "utf8.h" @@ -52,13 +53,44 @@ static int evh_cli(const struct event_io *, const ev_arg); static int cp_parse(struct cs_client *, char *, size_t, int); -static int mtpf_query(struct cs_client *, struct cp_head *, char *, size_t); +static int mtpf_query(struct cs_client *, struct mipc_head *, char *, size_t); +static int mtpf_if_list(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_ident_list(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_ident_add(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_ident_del(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_name_add(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_name_del(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_name_list(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_res_add(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_res_del(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_res_list(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_cache_flush(struct cs_client *, struct mipc_head *, char *, + size_t); +static int mtpf_cache_list(struct cs_client *, struct mipc_head *, char *f, + size_t); static void send_error(struct cs_client *, int, int); static void send_ack(struct cs_client *, int); -static int queryadd(struct cs_client *, struct csc_query *, int, int, int); -static int querydel(struct cs_client *, struct csc_query * , int); +static int queryadd(struct cs_client *, struct csc_query *, unsigned int, + int, int); +static int querydel(struct cs_client *, struct csc_query * , unsigned int); + +#define IPC_SETHDR(mih, id, type, len) \ + (mih)->mih_ver = MIPC_VERSION; \ + (mih)->mih_id = id; \ + (mih)->mih_msgtype = type; \ + (mih)->mih_msglen = len; /* * Open UNIX pipe socket to clients @@ -205,11 +237,12 @@ TAILQ_INSERT_TAIL(&cs->cs_head, csc, csc_next); csc->csc_sock = sock; csc->csc_serv = cs; + csc->csc_suser = 0; eva.ptr = csc; csc->csc_evid = event_add(g->g_evl, EVENT_TYPE_IO, evh_cli, &eva, evh_clisetup_init, &eva); - dprintf(DEBUG_CS, "New UNIX pipe client csc=%x", csc); + dprintf(DEBUG_CS, "New UNIX pipe client csc=%x, sock=%d", csc, sock); out: MTX_UNLOCK(cs, cs_mtx); return (0); @@ -270,11 +303,12 @@ struct cs_client *csc; struct cmsghdr *cmptr; struct sockcred *cred; - int n, sock, suser, error; + struct mipc_head *mih; + int n, sock, error, len; struct msghdr msg; struct iovec iov[1]; - char control[CMSG_LEN(SOCKCREDSIZE(1))]; - char buf[CP_MAXPLEN]; + char control[CMSG_LEN(SOCKCREDSIZE(1)) + sizeof(struct cmsghdr)]; + char buf[MIPC_MAXPLEN]; csc = arg.ptr; MDNS_INIT_ASSERT(csc, csc_magic); @@ -282,8 +316,6 @@ sock = csc->csc_sock; - iov[0].iov_base = buf; - iov[0].iov_len = CP_MAXPLEN; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; @@ -291,30 +323,43 @@ msg.msg_control = control; msg.msg_controllen = sizeof(control); msg.msg_flags = 0; + iov[0].iov_base = buf + sizeof(struct mipc_head); + + for (;;) { + n = read(sock, buf, sizeof(struct mipc_head)); + if (n < (signed int)sizeof(struct mipc_head)) + break; - n = recvmsg(sock, &msg, 0); - if (n < 0) - goto out; - cmptr = CMSG_FIRSTHDR(&msg); - suser = 0; - if (cmptr != NULL) { - if (cmptr->cmsg_type == SCM_CREDS && - cmptr->cmsg_level == SOL_SOCKET) { - cred = (struct sockcred *)CMSG_DATA(cmptr); - if (cred->sc_euid == 0) - suser = 1; + mih = (struct mipc_head *)buf; + if (mih->mih_ver != MIPC_VERSION) + continue; + + len = mih->mih_msglen > MIPC_MAXPLEN ? + MIPC_MAXPLEN : mih->mih_msglen; + iov[0].iov_len = len - sizeof(struct mipc_head); + + n = recvmsg(sock, &msg, 0); + if ((unsigned int)n != iov[0].iov_len) + continue; + + /* Check credentials */ + cmptr = CMSG_FIRSTHDR(&msg); + if (cmptr != NULL) { + if (cmptr->cmsg_type == SCM_CREDS && + cmptr->cmsg_level == SOL_SOCKET) { + cred = (struct sockcred *)CMSG_DATA(cmptr); + csc->csc_suser = (cred->sc_euid == 0) ? 1 : 0; + } } - } - dprintf(DEBUG_CS, "Received packet on UNIX pipe " - "csc=%x, len=%d, suser=%d", csc, n, suser); + dprintf(DEBUG_CS, "Received packet on UNIX pipe csc=%x, " + "len=%d, suser=%d, sock=%d", csc, n, csc->csc_suser, sock); - error = cp_parse(csc, buf, n, suser); - if (error != 0) { - dprintf(DEBUG_CS, "Failed to parse packet csc=%x", csc); - } + error = cp_parse(csc, buf, n, csc->csc_suser); + if (error != 0) + dprintf(DEBUG_CS, "Failed to parse packet csc=%x", csc); + } -out: MTX_UNLOCK(csc, csc_mtx); return (0); } @@ -322,7 +367,7 @@ /* * Parser defintions to individual message types. */ -typedef int (*mtp_func) (struct cs_client *, struct cp_head *, char *, size_t); +typedef int (*mtp_func) (struct cs_client *, struct mipc_head *, char *, size_t); struct msgtype_parser { int mtp_msgtype; /* message type */ int mtp_suser; /* super user privs required */ @@ -333,163 +378,1119 @@ * Table of recognized message types and their corresponding parser. */ static struct msgtype_parser mtp_table[] = { - { .mtp_msgtype = CPM_ACK, .mtp_suser = 0, .mtp_parser = NULL }, - { .mtp_msgtype = CPM_ERROR, .mtp_suser = 0, .mtp_parser = NULL }, - { .mtp_msgtype = CPM_QUERY, .mtp_suser = 0, .mtp_parser = mtpf_query } + { .mtp_msgtype = MIM_ACK, .mtp_suser = 0, .mtp_parser = NULL }, + { .mtp_msgtype = MIM_ERROR, .mtp_suser = 0, .mtp_parser = NULL }, + { .mtp_msgtype = MIM_QUERY, .mtp_suser = 0, .mtp_parser = mtpf_query }, + { .mtp_msgtype = MIM_IF_LIST, .mtp_suser = 1, + .mtp_parser = mtpf_if_list }, + { .mtp_msgtype = MIM_IDENT_LIST, .mtp_suser = 1, + .mtp_parser = mtpf_ident_list }, + { .mtp_msgtype = MIM_IDENT_ADD, .mtp_suser = 1, + .mtp_parser = mtpf_ident_add }, + { .mtp_msgtype = MIM_IDENT_DEL, .mtp_suser = 1, + .mtp_parser = mtpf_ident_del }, + { .mtp_msgtype = MIM_IDENT_NAME_ADD, .mtp_suser = 1, + .mtp_parser = mtpf_name_add }, + { .mtp_msgtype = MIM_IDENT_NAME_DEL, .mtp_suser = 1, + .mtp_parser = mtpf_name_del }, + { .mtp_msgtype = MIM_IDENT_NAME_LIST, .mtp_suser = 1, + .mtp_parser = mtpf_name_list }, + { .mtp_msgtype = MIM_IDENT_RES_ADD, .mtp_suser = 1, + .mtp_parser = mtpf_res_add }, + { .mtp_msgtype = MIM_IDENT_RES_DEL, .mtp_suser = 1, + .mtp_parser = mtpf_res_del }, + { .mtp_msgtype = MIM_IDENT_RES_LIST, .mtp_suser = 1, + .mtp_parser = mtpf_res_list }, + { .mtp_msgtype = MIM_CACHE_FLUSH, .mtp_suser = 1, + .mtp_parser = mtpf_cache_flush }, + { .mtp_msgtype = MIM_CACHE_LIST, .mtp_suser = 1, + .mtp_parser = mtpf_cache_list } }; static int mtp_table_size = sizeof(mtp_table) / sizeof(struct msgtype_parser); - /* * Parse packet received on UNIX pipe */ static int cp_parse(struct cs_client *csc, char *buf, size_t len, int suser) { - struct cp_head *cph; + struct mipc_head *mih; int i, error = 0; - if (len < sizeof(struct cp_head)) - return (CPE_IVAL); + + if (len < sizeof(struct mipc_head)) + return (-1); - cph = (struct cp_head *)buf; - if (cph->cph_ver != CP_VERSION) - return (CPE_IVAL); + mih = (struct mipc_head *)buf; + + dprintf(DEBUG_CS, "Header ver=%d, msgtype=%d", + mih->mih_ver, mih->mih_msgtype); + + if (mih->mih_ver != MIPC_VERSION) { + error = MIE_IVAL; + goto error; + } for (i = 0; i < mtp_table_size; i++) - if (cph->cph_msgtype == mtp_table[i].mtp_msgtype) + if (mih->mih_msgtype == mtp_table[i].mtp_msgtype) break; - if (i == mtp_table_size) - return (CPE_IVAL); + if (i == mtp_table_size) { + error = MIE_IVAL; + goto error; + } - if (mtp_table[i].mtp_suser && !suser) - return (CPE_PERM); - - dprintf(DEBUG_CS, "Header ver=%d, msgtype=%d", - cph->cph_ver, cph->cph_msgtype); + if (mtp_table[i].mtp_suser && !suser) { + dprintf(DEBUG_CS, "Privileged request from non-root user " + "csc=%x", csc); + error = MIE_PERM; + goto error; + } if (mtp_table[i].mtp_parser != NULL) { - error = mtp_table[i].mtp_parser(csc, cph, - buf + sizeof(struct cp_head), - len - sizeof(struct cp_head)); + error = mtp_table[i].mtp_parser(csc, mih, + buf + sizeof(struct mipc_head), + len - sizeof(struct mipc_head)); } if (error != 0) - send_error(csc, cph->cph_id, error); + goto error; - return (error); + return (0); +error: + send_error(csc, mih->mih_id, error); + return (-1); } /* * Query parser */ static int -mtpf_query(struct cs_client *csc, struct cp_head *cph, char *buf, size_t len) +mtpf_query(struct cs_client *csc, struct mipc_head *mih, char *buf, size_t len) { - struct cp_query *cpq; + struct mipc_query *miq; wchar_t *wp; int error, retval = 0; struct csc_query cscq; wchar_t name[MDNS_RECORD_LEN+1]; - if (len < sizeof(struct cp_query)) - return (CPE_IVAL); + if (len < sizeof(struct mipc_query)) + return (MIE_IVAL); - cpq = (struct cp_query *)buf; - if ((cpq->cpq_len * sizeof(wchar_t)) + sizeof(struct cp_query) != len) - return (CPE_IVAL); + miq = (struct mipc_query *)buf; + if ((miq->miq_len * sizeof(wchar_t)) + sizeof(struct mipc_query) != len) + return (MIE_IVAL); - wp = (wchar_t *)(buf + sizeof(struct cp_query)); - memcpy(name, wp, cpq->cpq_len * sizeof(wchar_t)); - name[cpq->cpq_len] = L'\0'; + wp = (wchar_t *)(buf + sizeof(struct mipc_query)); + memcpy(name, wp, miq->miq_len * sizeof(wchar_t)); + name[miq->miq_len] = L'\0'; error = utf8_encode(name, cscq.cscq_qs.name, MDNS_RECORD_LEN); if (error < 0) - return (CPE_IVAL); + return (MIE_IVAL); dprintf(DEBUG_CS,"Query message class=%d, type=%d, name=%ls, " - "cmd=%d, fam=%d, ifidx=%d, timeout=%d", cpq->cpq_class, - cpq->cpq_type, name, cpq->cpq_cmd, cpq->cpq_fam, - cpq->cpq_ifidx, cpq->cpq_timeout); + "cmd=%d, fam=%d, ifidx=%d, timeout=%d", miq->miq_class, + miq->miq_type, name, miq->miq_cmd, miq->miq_fam, + miq->miq_ifidx, miq->miq_timeout); cscq.cscq_qs.q_name = cscq.cscq_qs.name; - cscq.cscq_qs.q_type = cpq->cpq_type; - cscq.cscq_qs.q_class = cpq->cpq_class; - cscq.cscq_id = cph->cph_id; + cscq.cscq_qs.q_type = miq->miq_type; + cscq.cscq_qs.q_class = miq->miq_class; + cscq.cscq_id = mih->mih_id; cscq.cscq_resp = 0; cscq.cscq_csc = csc; MDNS_INIT_SET(&cscq, cscq_magic); - switch (cpq->cpq_cmd) { - case CPQ_CMD_ONESHOT: - error = queryadd(csc, &cscq, cpq->cpq_ifidx, cpq->cpq_fam, - cpq->cpq_timeout); + switch (miq->miq_cmd) { + case MIQ_CMD_ONESHOT: + error = queryadd(csc, &cscq, miq->miq_ifidx, miq->miq_fam, + miq->miq_timeout); if (error != 0) - retval = CPE_IVAL; + retval = MIE_IVAL; break; - case CPQ_CMD_CREG: - error = queryadd(csc, &cscq, cpq->cpq_ifidx, cpq->cpq_fam, 0); + case MIQ_CMD_CREG: + error = queryadd(csc, &cscq, miq->miq_ifidx, miq->miq_fam, 0); if (error == 0) - send_ack(csc, cph->cph_id); + send_ack(csc, mih->mih_id); else - retval = CPE_REGQ; + retval = MIE_REGQ; break; - case CPQ_CMD_CDEREG: - error = querydel(csc, &cscq, cpq->cpq_ifidx); + case MIQ_CMD_CDEREG: + error = querydel(csc, &cscq, miq->miq_ifidx); if (error == 0) - send_ack(csc, cph->cph_id); + send_ack(csc, mih->mih_id); else - retval = CPE_DEREGQ; + retval = MIE_DEREGQ; break; default: - return (CPE_IVAL); + return (MIE_IVAL); + } + + return (0); +} + +/* + * List active interfaces + */ +static int +mtpf_if_list(struct cs_client *csc, struct mipc_head *mih, char *buf __unused, + size_t len) +{ + struct md_glob *g; + struct md_if *mif; + size_t iflen; + struct mipc_if miif; + struct mipc_head rmih; + struct iovec iov[3]; + + if (len != 0) + return (MIE_IVAL); + + dprintf(DEBUG_CS, "Interface list request csc=%x", csc); + + g = csc->csc_serv->cs_glob; + IPC_SETHDR(&rmih, mih->mih_id, MIM_IF, 0); + iov[0].iov_base = &rmih; + iov[0].iov_len = sizeof(struct mipc_head); + iov[1].iov_base = &miif; + iov[1].iov_len = sizeof(struct mipc_if); + + RW_RLOCK(g, g_lock); + TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) { + iflen = strlen(mif->mif_ifnam); + iov[2].iov_base = mif->mif_ifnam; + iov[2].iov_len = iflen; + miif.miif_ifidx = mif->mif_index; + miif.miif_len = iflen; + miif.miif_flags = 0; + rmih.mih_msglen = + sizeof(struct mipc_head) + sizeof(struct mipc_if) + iflen; + writev(csc->csc_sock, iov, 3); + } + + RW_UNLOCK(g, g_lock); + send_ack(csc, mih->mih_id); + return (0); +} + +/* + * List database record idents + */ +static int +mtpf_ident_list(struct cs_client *csc, struct mipc_head *mih, char *buf, + size_t len) +{ + struct mipc_dbi_list *miil; + struct md_glob *g; + struct md_if *mif; + char **ident; + int i, ilen; + struct mipc_dbident mii; + struct mipc_head rmih; + struct iovec iov[3]; + + if (len < sizeof(struct mipc_dbi_list)) + return (MIE_IVAL); + + miil = (struct mipc_dbi_list *)buf; + g = csc->csc_serv->cs_glob; + + if (miil->miil_ifidx > g->g_ifs_max) + return (MIE_IVAL); + + mif = g->g_ifs[miil->miil_ifidx]; + if (mif == NULL) + return (MIE_IVAL); + + IPC_SETHDR(&rmih, mih->mih_id, MIM_IDENT, 0); + iov[0].iov_base = &rmih; + iov[0].iov_len = sizeof(struct mipc_head); + iov[1].iov_base = &mii; + iov[1].iov_len = sizeof(struct mipc_dbident); + mii.mii_ifidx = mif->mif_index; + + ident = dbr_ident_list(&mif->mif_dbr); + + i = 0; + while (ident[i] != NULL) { + ilen = strlen(ident[i]); + rmih.mih_msglen = sizeof(struct mipc_head) + + sizeof(struct mipc_dbident) + ilen; + mii.mii_len = ilen; + iov[2].iov_base = ident[i]; + iov[2].iov_len = ilen; + writev(csc->csc_sock, iov, 3); + i++; + } + + dprintf(DEBUG_CS, "Sent identifier list to client, csc=%x", csc); + + send_ack(csc, mih->mih_id); + dbr_ident_list_free(ident); + return (0); +} + +/* + * IPC MIM_IDENT_ADD - Add an itentifier to the record database + * The message type MIM_IDENT_ADD allows a privileged client to add + * a new resource identifier to the record database, either to a specific + * interface index or to all active interfaces. + */ +static int +mtpf_ident_add(struct cs_client *csc, struct mipc_head *mih, char *buf, + size_t len) +{ + struct mipc_dbident *mii; + struct md_glob *g; + struct md_if *mif; + char *ident, *p; + int error = 0; + + g = csc->csc_serv->cs_glob; + + if (len < sizeof(struct mipc_dbident)) + return (MIE_IVAL); + + mii = (struct mipc_dbident *)buf; + p = buf + sizeof(struct mipc_dbident); + len -= sizeof(struct mipc_dbident); + + if (mii->mii_ifidx > g->g_ifs_max) + return (MIE_IVAL); + + if (mii->mii_len > len) + return (MIE_IVAL); + + ident = malloc(mii->mii_len + 1); + if (ident == NULL) + return (MIE_INTE); + memcpy(ident, p, mii->mii_len); + ident[mii->mii_len] = '\0'; + + dprintf(DEBUG_CS, "Request to add resource identifier %s, ifidx=%d " + "csc=%x", ident, mii->mii_ifidx, csc); + + RW_RLOCK(g, g_lock); + + /* + * Only add the identifier to a specific interface index + * if one was specified in the message. + */ + if (mii->mii_ifidx != 0) { + mif = g->g_ifs[mii->mii_ifidx]; + if (mif == NULL) { + RW_UNLOCK(g, g_lock); + free(ident); + return (MIE_IVAL); + } + error = dbr_ident_add(&mif->mif_dbr, ident); + } + else { + /* We ignore errors in this case */ + TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) { + dbr_ident_add(&mif->mif_dbr, ident); + } + } + + RW_UNLOCK(g, g_lock); + free(ident); + if (error < 0) + return (MIE_EXISTS); + + send_ack(csc, mih->mih_id); + return (0); +} + +/* + * IPC MIM_IDENT_DEL - Remove an identifier from the record database + */ +static int +mtpf_ident_del(struct cs_client *csc, struct mipc_head *mih, char *buf, + size_t len) +{ + struct mipc_dbident *mii; + struct md_glob *g; + struct md_if *mif; + char *p, *ident; + int error = 0; + + g = csc->csc_serv->cs_glob; + + if (len < sizeof(struct mipc_dbident)) + return (MIE_IVAL); + + mii = (struct mipc_dbident *)buf; + p = buf + sizeof(struct mipc_dbident); + len -= sizeof(struct mipc_dbident); + + if (mii->mii_ifidx > g->g_ifs_max) + return (MIE_IVAL); + + if (mii->mii_len > len) + return (MIE_IVAL); + + ident = malloc(mii->mii_len + 1); + if (ident == NULL) + return (MIE_INTE); + memcpy(ident, p, mii->mii_len); + ident[mii->mii_len] = '\0'; + + dprintf(DEBUG_CS, "Request to remove identifier %s, ifidx=%d, csc=%x", + ident, mii->mii_ifidx, csc); + + RW_RLOCK(g, g_lock); + + if (mii->mii_ifidx != 0) { + mif = g->g_ifs[mii->mii_ifidx]; + if (mif == NULL) { + RW_UNLOCK(g, g_lock); + free(ident); + return (MIE_IVAL); + } + error = dbr_ident_del(&mif->mif_dbr, ident); + } + else { + TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) { + dbr_ident_del(&mif->mif_dbr, ident); + } + } + + RW_UNLOCK(g, g_lock); + free(ident); + if (error < 0) + return (MIE_EXISTS); + + send_ack(csc, mih->mih_id); + return (0); +} + +static int +parse_dbi_name(char *buf, size_t len, struct mipc_dbi_name **miin, char **ident, + wchar_t **name) +{ + char *p; + struct mipc_dbi_name *miin2; + + if (len < sizeof(struct mipc_dbi_name)) + return (MIE_IVAL); + + *miin = (struct mipc_dbi_name *)buf; + len -= sizeof(struct mipc_dbi_name); + p = buf + sizeof(struct mipc_dbi_name); + + miin2 = *miin; + + if (len < miin2->miin_ilen) + return (MIE_IVAL); + + *ident = malloc(miin2->miin_ilen + 1); + if (*ident == NULL) + return (MIE_INTE); + memcpy(*ident, p, miin2->miin_ilen); + *ident[miin2->miin_ilen] = '\0'; + p += miin2->miin_ilen; + len -= miin2->miin_ilen; + + if (len < miin2->miin_len) { + free(*ident); + return (MIE_IVAL); + } + + *name = malloc((miin2->miin_len + 1) * sizeof(wchar_t)); + if (*name == NULL) { + free(*ident); + return (MIE_IVAL); + } + memcpy(*name, p, miin2->miin_len * sizeof(wchar_t)); + *name[miin2->miin_len] = L'\0'; + + return (0); +} + +/* + * IPC MIM_IDENT_NAME_ADD - Add a name record to a resource identifier + */ +static int +mtpf_name_add(struct cs_client *csc, struct mipc_head *mih, char *buf, + size_t len) +{ + struct md_glob *g; + struct md_if *mif; + struct mipc_dbi_name *miin; + wchar_t *name; + char *ident; + int error, retval = 0; + + error = parse_dbi_name(buf, len, &miin, &ident, &name); + if (error != 0) + return (error); + + g = csc->csc_serv->cs_glob; + + dprintf(DEBUG_CS, "Request to add name %ls to identifier %s, " + "csc=%x, ifidx=%d", name, ident, csc, miin->miin_ifidx); + + RW_RLOCK(g, g_lock); + + if (miin->miin_ifidx > g->g_ifs_max) + goto error; + + if (miin->miin_ifidx != 0) { + mif = g->g_ifs[miin->miin_ifidx]; + if (mif == NULL) + goto error; + error = dbr_name_add(&mif->mif_dbr, ident, name); + if (error != 0) + retval = MIE_NOENT; + } + else { + TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) { + dbr_name_add(&mif->mif_dbr, ident, name); + } + } + + RW_UNLOCK(g, g_lock); + free(ident); + free(name); + if (retval == 0) + send_ack(csc, mih->mih_id); + return (retval); +error: + RW_UNLOCK(g, g_lock); + free(ident); + free(name); + return (MIE_IVAL); +} + +/* + * IPC MIM_IDENT_NAME_DEL - Remove a name from a resource identifier + */ +static int +mtpf_name_del(struct cs_client *csc, struct mipc_head *mih, char *buf, + size_t len) +{ + struct md_glob *g; + struct md_if *mif; + struct mipc_dbi_name *miin; + wchar_t *name; + char *ident; + int error, retval = 0; + + error = parse_dbi_name(buf, len, &miin, &ident, &name); + if (error != 0) + return (error); + + g = csc->csc_serv->cs_glob; + + dprintf(DEBUG_CS, "Request to remove name %ls to identifier %s, " + "csc=%x, ifidx=%d", name, ident, csc, miin->miin_ifidx); + + RW_RLOCK(g, g_lock); + + if (miin->miin_ifidx > g->g_ifs_max) + goto error; + + if (miin->miin_ifidx != 0) { + mif = g->g_ifs[miin->miin_ifidx]; + if (mif == NULL) + goto error; + error = dbr_name_add(&mif->mif_dbr, ident, name); + if (error != 0) + retval = MIE_EXISTS; + } + else { + TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) { + dbr_name_add(&mif->mif_dbr, ident, name); + } + } + + RW_UNLOCK(g, g_lock); + free(ident); + free(name); + if (retval == 0) + send_ack(csc, mih->mih_id); + return (retval); +error: + RW_UNLOCK(g, g_lock); + free(ident); + free(name); + return (error); +} + +/* + * IPC MIM_IDENT_NAME_LIST - Return a list of names on an identifier + */ +static int +mtpf_name_list(struct cs_client *csc, struct mipc_head *mih, char *buf, + size_t len) +{ + struct md_glob *g; + struct md_if *mif; + struct mipc_dbi_name_list *miinl; + char *ident, *p; + struct dbr_name *dn; + int retval = 0; + size_t namlen, nlen, i; + struct mipc_dbi_name miin; + struct mipc_head rmih; + struct iovec iov[5]; + + if (len < sizeof(struct mipc_dbi_name_list)) + return (MIE_IVAL); + + miinl = (struct mipc_dbi_name_list *)buf; + p = buf + sizeof(struct mipc_dbi_name_list); + len -= sizeof(struct mipc_dbi_name_list); + + if (len < miinl->miinl_ilen) + return (MIE_IVAL); + + ident = malloc(miinl->miinl_ilen + 0); + if (ident == NULL) + return (MIE_INTE); + memcpy(ident, p, miinl->miinl_ilen); + ident[miinl->miinl_ilen] = '\0'; + + dprintf(DEBUG_CS, "Request to list names on identifier %s, " + "csc=%x, ifidx=%d", ident, csc, miinl->miinl_ifidx); + + if (miinl->miinl_ifidx == 0) + return (MIE_IVAL); + + g = csc->csc_serv->cs_glob; + RW_RLOCK(g, g_lock); + + mif = g->g_ifs[miinl->miinl_ifidx]; + if (mif == NULL) { + retval = MIE_IVAL; + goto out; + } + + dn = dbr_name_list(&mif->mif_dbr, ident, &namlen); + if (dn == NULL) { + retval = MIE_INTE; + goto out; + } + + miin.miin_ifidx = mif->mif_index; + miin.miin_zero = 0; + + RW_UNLOCK(g, g_lock); + + IPC_SETHDR(&rmih, mih->mih_id, MIM_IDENT_NAME, 0); + iov[0].iov_base = &rmih; + iov[0].iov_len = sizeof(struct mipc_head); + iov[1].iov_base = &miin; + iov[1].iov_len = sizeof(struct mipc_dbi_name); + iov[2].iov_base = ident; + iov[2].iov_len = miinl->miinl_ilen; + miin.miin_ilen = miinl->miinl_ilen; + + for (i = 0; i < namlen; i++) { + rmih.mih_msglen = sizeof(struct mipc_head) + + sizeof(struct mipc_dbi_name) + miinl->miinl_ilen; + + len = wcslen(dn[i].dn_name); + iov[3].iov_base = dn[i].dn_name; + iov[3].iov_len = len * sizeof(wchar_t); + rmih.mih_msglen += nlen; + miin.miin_len = nlen; + + if (dn[i].dn_ename != NULL) { + len = wcslen(dn[i].dn_ename); + iov[4].iov_base = dn[i].dn_ename; + iov[4].iov_len = len * sizeof(wchar_t); + rmih.mih_msglen += nlen; + miin.miin_elen = nlen; + } + else { + iov[4].iov_base = NULL; + iov[4].iov_len = 0; + miin.miin_elen = 0; + } + writev(csc->csc_sock, iov, 5); + } + + dbr_name_list_free(dn, namlen); + send_ack(csc, mih->mih_id); + return (0); +out: + RW_UNLOCK(g, g_lock); + free(ident); + return (retval); +} + +/* + * Parse MIM_IDENT_RES_{ADD,DEL} messages, helper do mtpf_res_{add,del} + */ +static int +parse_res_set(char *buf, size_t len, struct mipc_dbi_res_set **mirs, + char **ident, wchar_t **res, char **resptr) +{ + struct mipc_dbi_res_set *mirs2; + char *p; + + if (len < sizeof(struct mipc_dbi_res_set)) + return (MIE_IVAL); + + *mirs = (struct mipc_dbi_res_set *)buf; + mirs2 = *mirs; + + p = buf + sizeof(struct mipc_dbi_res_set); + len -= sizeof(struct mipc_dbi_res_set); + + if (len < mirs2->mirs_ilen) + return (MIE_IVAL); + + *ident = malloc(mirs2->mirs_ilen + 1); + if (*ident == NULL) + return (MIE_INTE); + memcpy(*ident, p, mirs2->mirs_ilen); + *ident[mirs2->mirs_ilen] = '\0'; + p += mirs2->mirs_ilen; + len -= mirs2->mirs_ilen; + + *res = NULL; + *resptr = NULL; + + if (mirs2->mirs_pointer) { + if (len < mirs2->mirs_rlen) { + free(*ident); + return (MIE_IVAL); + } + + *resptr = malloc(mirs2->mirs_rlen + 1); + if (*resptr == NULL) { + free(*ident); + return (MIE_IVAL); + } + memcpy(*resptr, p, mirs2->mirs_rlen); + *resptr[mirs2->mirs_rlen] = '\0'; + } + else { + if (len < (mirs2->mirs_rlen * sizeof(wchar_t))) { + free(*ident); + return (MIE_IVAL); + } + + *res = malloc((mirs2->mirs_rlen + 1) * sizeof(wchar_t)); + if (*res == NULL) { + free(*ident); + return (MIE_INTE); + } + memcpy(*res, p, mirs2->mirs_rlen * sizeof(wchar_t)); + *res[mirs2->mirs_rlen] = L'\0'; + } + + return (0); +} + +/* + * IPC MIM_IDENT_RES_ADD - Add a resource to an identifier + */ +static int +mtpf_res_add(struct cs_client *csc, struct mipc_head *mih, char *buf, + size_t len) +{ + struct md_glob *g; + struct md_if *mif; + struct mipc_dbi_res_set *mirs; + wchar_t *rres; + char *ident, *resptr; + void *res; + int error, ptr; + + error = parse_res_set(buf, len, &mirs, &ident, &rres, &resptr); + if (error != 0) + return (error); + res = (rres != NULL) ? (void *)rres : (void *)resptr; + ptr = (resptr != NULL); + + g = csc->csc_serv->cs_glob; + RW_RLOCK(g, g_lock); + if (mirs->mirs_ifidx > g->g_ifs_max) + goto out; + + error = 0; + if (mirs->mirs_ifidx != 0) { + mif = g->g_ifs[mirs->mirs_ifidx]; + if (mif == NULL) + goto out; + error = dbr_res_add(&mif->mif_dbr, ident, mirs->mirs_class, + mirs->mirs_type, mirs->mirs_ttl, res, ptr); + } + else { + TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) { + dbr_res_add(&mif->mif_dbr, ident, mirs->mirs_class, + mirs->mirs_type, mirs->mirs_ttl, res, ptr); + } + } + RW_UNLOCK(g, g_lock); >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200708051859.l75IxPJj044037>