void handle_command(const char *cmd, unsigned a0, unsigned a1, unsigned a2) { if(startswith(cmd,"flash:")) { handle_flash(cmd + 6, a0, a1); return; } if(startswith(cmd,"dump:")) { handle_dump(cmd + 5, a0); return; } jtag_fail("unknown command"); }
static void read_from_cmd_socket(int sock_fd, int event, void *anything) { CMD_Request rx_message; CMD_Reply tx_message; int status, read_length, expected_length, rx_message_length; int localhost, allowed, log_index; union sockaddr_all where_from; socklen_t from_length; IPAddr remote_ip; unsigned short remote_port, rx_command; struct timeval now, cooked_now; rx_message_length = sizeof(rx_message); from_length = sizeof(where_from); status = recvfrom(sock_fd, (char *)&rx_message, rx_message_length, 0, &where_from.sa, &from_length); if (status < 0) { LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket %d", strerror(errno), sock_fd); return; } if (from_length > sizeof (where_from) || from_length <= sizeof (where_from.sa.sa_family)) { DEBUG_LOG(LOGF_CmdMon, "Read command packet without source address"); return; } read_length = status; /* Get current time cheaply */ SCH_GetLastEventTime(&cooked_now, NULL, &now); UTI_SockaddrToIPAndPort(&where_from.sa, &remote_ip, &remote_port); /* Check if it's from localhost (127.0.0.1, ::1, or Unix domain) */ switch (remote_ip.family) { case IPADDR_INET4: assert(sock_fd == sock_fd4); localhost = remote_ip.addr.in4 == INADDR_LOOPBACK; break; #ifdef FEAT_IPV6 case IPADDR_INET6: assert(sock_fd == sock_fd6); localhost = !memcmp(remote_ip.addr.in6, &in6addr_loopback, sizeof (in6addr_loopback)); break; #endif case IPADDR_UNSPEC: /* This should be the Unix domain socket */ if (where_from.sa.sa_family != AF_UNIX) return; assert(sock_fd == sock_fdu); localhost = 1; break; default: assert(0); } DEBUG_LOG(LOGF_CmdMon, "Received %d bytes from %s fd %d", status, UTI_SockaddrToString(&where_from.sa), sock_fd); if (!(localhost || ADF_IsAllowed(access_auth_table, &remote_ip))) { /* The client is not allowed access, so don't waste any more time on him. Note that localhost is always allowed access regardless of the defined access rules - otherwise, we could shut ourselves out completely! */ return; } if (read_length < offsetof(CMD_Request, data) || read_length < offsetof(CMD_Reply, data) || rx_message.pkt_type != PKT_TYPE_CMD_REQUEST || rx_message.res1 != 0 || rx_message.res2 != 0) { /* We don't know how to process anything like this or an error reply would be larger than the request */ DEBUG_LOG(LOGF_CmdMon, "Command packet dropped"); return; } expected_length = PKL_CommandLength(&rx_message); rx_command = ntohs(rx_message.command); tx_message.version = PROTO_VERSION_NUMBER; tx_message.pkt_type = PKT_TYPE_CMD_REPLY; tx_message.res1 = 0; tx_message.res2 = 0; tx_message.command = rx_message.command; tx_message.reply = htons(RPY_NULL); tx_message.status = htons(STT_SUCCESS); tx_message.pad1 = 0; tx_message.pad2 = 0; tx_message.pad3 = 0; tx_message.sequence = rx_message.sequence; tx_message.pad4 = 0; tx_message.pad5 = 0; if (rx_message.version != PROTO_VERSION_NUMBER) { DEBUG_LOG(LOGF_CmdMon, "Command packet has invalid version (%d != %d)", rx_message.version, PROTO_VERSION_NUMBER); if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) { tx_message.status = htons(STT_BADPKTVERSION); transmit_reply(&tx_message, &where_from); } return; } if (rx_command >= N_REQUEST_TYPES || expected_length < (int)offsetof(CMD_Request, data)) { DEBUG_LOG(LOGF_CmdMon, "Command packet has invalid command %d", rx_command); tx_message.status = htons(STT_INVALID); transmit_reply(&tx_message, &where_from); return; } if (read_length < expected_length) { DEBUG_LOG(LOGF_CmdMon, "Command packet is too short (%d < %d)", read_length, expected_length); tx_message.status = htons(STT_BADPKTLENGTH); transmit_reply(&tx_message, &where_from); return; } /* OK, we have a valid message. Now dispatch on message type and process it. */ log_index = CLG_LogCommandAccess(&remote_ip, &cooked_now); /* Don't reply to all requests from hosts other than localhost if the rate is excessive */ if (!localhost && log_index >= 0 && CLG_LimitCommandResponseRate(log_index)) { DEBUG_LOG(LOGF_CmdMon, "Command packet discarded to limit response rate"); return; } if (rx_command >= N_REQUEST_TYPES) { /* This should be already handled */ assert(0); } else { /* Check level of authority required to issue the command. All commands from the Unix domain socket (which is accessible only by the root and chrony user/group) are allowed. */ if (where_from.sa.sa_family == AF_UNIX) { assert(sock_fd == sock_fdu); allowed = 1; } else { switch (permissions[rx_command]) { case PERMIT_AUTH: allowed = 0; break; case PERMIT_LOCAL: allowed = localhost; break; case PERMIT_OPEN: allowed = 1; break; default: assert(0); allowed = 0; } } if (allowed) { switch(rx_command) { case REQ_NULL: /* Do nothing */ break; case REQ_DUMP: handle_dump(&rx_message, &tx_message); break; case REQ_ONLINE: handle_online(&rx_message, &tx_message); break; case REQ_OFFLINE: handle_offline(&rx_message, &tx_message); break; case REQ_BURST: handle_burst(&rx_message, &tx_message); break; case REQ_MODIFY_MINPOLL: handle_modify_minpoll(&rx_message, &tx_message); break; case REQ_MODIFY_MAXPOLL: handle_modify_maxpoll(&rx_message, &tx_message); break; case REQ_MODIFY_MAXDELAY: handle_modify_maxdelay(&rx_message, &tx_message); break; case REQ_MODIFY_MAXDELAYRATIO: handle_modify_maxdelayratio(&rx_message, &tx_message); break; case REQ_MODIFY_MAXDELAYDEVRATIO: handle_modify_maxdelaydevratio(&rx_message, &tx_message); break; case REQ_MODIFY_MAXUPDATESKEW: handle_modify_maxupdateskew(&rx_message, &tx_message); break; case REQ_MODIFY_MAKESTEP: handle_modify_makestep(&rx_message, &tx_message); break; case REQ_LOGON: /* Authentication is no longer supported, log-on always fails */ tx_message.status = htons(STT_FAILED); break; case REQ_SETTIME: handle_settime(&rx_message, &tx_message); break; case REQ_LOCAL2: handle_local(&rx_message, &tx_message); break; case REQ_MANUAL: handle_manual(&rx_message, &tx_message); break; case REQ_N_SOURCES: handle_n_sources(&rx_message, &tx_message); break; case REQ_SOURCE_DATA: handle_source_data(&rx_message, &tx_message); break; case REQ_REKEY: handle_rekey(&rx_message, &tx_message); break; case REQ_ALLOW: handle_allowdeny(&rx_message, &tx_message, 1, 0); break; case REQ_ALLOWALL: handle_allowdeny(&rx_message, &tx_message, 1, 1); break; case REQ_DENY: handle_allowdeny(&rx_message, &tx_message, 0, 0); break; case REQ_DENYALL: handle_allowdeny(&rx_message, &tx_message, 0, 1); break; case REQ_CMDALLOW: handle_cmdallowdeny(&rx_message, &tx_message, 1, 0); break; case REQ_CMDALLOWALL: handle_cmdallowdeny(&rx_message, &tx_message, 1, 1); break; case REQ_CMDDENY: handle_cmdallowdeny(&rx_message, &tx_message, 0, 0); break; case REQ_CMDDENYALL: handle_cmdallowdeny(&rx_message, &tx_message, 0, 1); break; case REQ_ACCHECK: handle_accheck(&rx_message, &tx_message); break; case REQ_CMDACCHECK: handle_cmdaccheck(&rx_message, &tx_message); break; case REQ_ADD_SERVER: handle_add_source(NTP_SERVER, &rx_message, &tx_message); break; case REQ_ADD_PEER: handle_add_source(NTP_PEER, &rx_message, &tx_message); break; case REQ_DEL_SOURCE: handle_del_source(&rx_message, &tx_message); break; case REQ_WRITERTC: handle_writertc(&rx_message, &tx_message); break; case REQ_DFREQ: handle_dfreq(&rx_message, &tx_message); break; case REQ_DOFFSET: handle_doffset(&rx_message, &tx_message); break; case REQ_TRACKING: handle_tracking(&rx_message, &tx_message); break; case REQ_SMOOTHING: handle_smoothing(&rx_message, &tx_message); break; case REQ_SMOOTHTIME: handle_smoothtime(&rx_message, &tx_message); break; case REQ_SOURCESTATS: handle_sourcestats(&rx_message, &tx_message); break; case REQ_RTCREPORT: handle_rtcreport(&rx_message, &tx_message); break; case REQ_TRIMRTC: handle_trimrtc(&rx_message, &tx_message); break; case REQ_CYCLELOGS: handle_cyclelogs(&rx_message, &tx_message); break; case REQ_CLIENT_ACCESSES_BY_INDEX2: handle_client_accesses_by_index(&rx_message, &tx_message); break; case REQ_MANUAL_LIST: handle_manual_list(&rx_message, &tx_message); break; case REQ_MANUAL_DELETE: handle_manual_delete(&rx_message, &tx_message); break; case REQ_MAKESTEP: handle_make_step(&rx_message, &tx_message); break; case REQ_ACTIVITY: handle_activity(&rx_message, &tx_message); break; case REQ_RESELECTDISTANCE: handle_reselect_distance(&rx_message, &tx_message); break; case REQ_RESELECT: handle_reselect(&rx_message, &tx_message); break; case REQ_MODIFY_MINSTRATUM: handle_modify_minstratum(&rx_message, &tx_message); break; case REQ_MODIFY_POLLTARGET: handle_modify_polltarget(&rx_message, &tx_message); break; case REQ_REFRESH: handle_refresh(&rx_message, &tx_message); break; case REQ_SERVER_STATS: handle_server_stats(&rx_message, &tx_message); break; default: DEBUG_LOG(LOGF_CmdMon, "Unhandled command %d", rx_command); tx_message.status = htons(STT_FAILED); break; } } else { tx_message.status = htons(STT_UNAUTH); } } /* Transmit the response */ { /* Include a simple way to lose one message in three to test resend */ static int do_it=1; if (do_it) { transmit_reply(&tx_message, &where_from); } #if 0 do_it = ((do_it + 1) % 3); #endif } }
void magic_button(s16 key) { switch (key) { case PGKEY_SLASH: /* CTRL-ALT-SLASH exits */ pgserver_mainloop_stop(); return; #ifdef DEBUG_KEYS /* The rest only work in debug mode */ case PGKEY_d: /* CTRL-ALT-d lists all debugging commands */ guru("Someone set up us the bomb!\n" "All your divnode are belong to us!\n" "\n" "Debugging keys:\n" " CTRL-ALT-H: [H]andle tree dump to stdout\n" " CTRL-ALT-S: [S]tring dump to stdout\n" " CTRL-ALT-T: Div[t]ree dump to stdout\n" " CTRL-ALT-M: [M]emory use profile\n" " CTRL-ALT-B: [B]lack screen\n" " CTRL-ALT-Y: Uns[y]nchronize screen buffers\n" " CTRL-ALT-U: Bl[u]e screen\n" " CTRL-ALT-P: Bitma[p] dump to video display\n" " CTRL-ALT-O: Divn[o]de outline\n" " CTRL-ALT-A: [A]pplication dump to stdout\n" " CTRL-ALT-R: Hotspot g[r]aph\n" " CTRL-ALT-I: Mode [I]nfo\n" ); return; case PGKEY_h: /* CTRL-ALT-h dumps the handle tree */ handle_dump(); return; case PGKEY_s: /* CTRL-ALT-s dumps all strings */ string_dump(); return; case PGKEY_n: /* CTRL-ALT-n dumps all gropnodes */ grop_dump(); return; case PGKEY_t: /* CTRL-ALT-t dumps all divnodes */ div_dump(); return; case PGKEY_g: /* Just for fun :) */ guru("GURU MEDITATION #3263827\n\nCongratulations!\n" " Either you have read the source code or\n" " you have very persistently banged your\n" " head on the keyboard ;-)"); return; case PGKEY_m: /* CTRL-ALT-m displays a memory profile */ guru("Memory Profile\n\n" "Total memory use: %d bytes in %d allocations\n\n" "%d bytes in %d gropnodes\n" "%d bytes in %d zombie gropnodes\n" "%d bytes in %d divnodes\n" "%d bytes in %d widgets\n" "%d bytes in %d handle nodes", memamt,memref, num_grops*sizeof(struct gropnode),num_grops, grop_zombie_count*sizeof(struct gropnode),grop_zombie_count, num_divs*sizeof(struct divnode),num_divs, num_widgets*sizeof(struct widget),num_widgets, num_handles*sizeof(struct handlenode),num_handles); return; case PGKEY_b: /* CTRL-ALT-b blanks the screen */ { s16 lxres,lyres; VID(bitmap_getsize)(magic_cursor_display(), &lxres, &lyres); VID(rect) (magic_cursor_display(), 0,0,lxres,lyres, VID(color_pgtohwr) (0),PG_LGOP_NONE); VID(update) (magic_cursor_display(),0,0,lxres,lyres); } return; case PGKEY_y: /* CTRL-ALT-y unsynchronizes the screen buffers */ { /* The buffers in PicoGUI normally like to be synchronized. * Data flows from the divtree to the backbuffer to the screen. * The purpose of this debugging key is to put a different * image on the screen (a black rectangle) than is in the rest * of the pipeline, so that by watching the data ooze out one * can tell if the correct update regions are being used and * in general prod at the video driver. * This would be very simple if not for the fact that only the video * driver has access to the screen's buffer. The procedure here is * to pump the black screen all the way through, then reinitializing * the backbuffer while being very carefull not to update right away * or mess up the sprites. */ struct divtree *p; s16 lxres,lyres; VID(bitmap_getsize)(magic_cursor_display(), &lxres, &lyres); /* Push through the black screen */ VID(rect) (magic_cursor_display(), 0,0,lxres,lyres, VID(color_pgtohwr) (0),PG_LGOP_NONE); VID(update) (magic_cursor_display(),0,0,lxres,lyres); /* Force redrawing everything to the backbuffer */ for (p=dts->top;p;p=p->next) p->flags |= DIVTREE_ALL_REDRAW; update(NULL,0); /* Note the zero flag! */ /* Clear the update rectangle, breaking the pipeline that usually works so well :) */ for (p=dts->top;p;p=p->next) p->update_rect.w = 0; /* The above zero flag left sprites off. With sprites off it's tough to use the mouse! */ VID(sprite_showall) (); } return; case PGKEY_u: /* CTRL-ALT-u makes a blue screen */ { s16 lxres,lyres; VID(bitmap_getsize)(magic_cursor_display(), &lxres, &lyres); VID(rect) (magic_cursor_display(),0,0,lxres,lyres, VID(color_pgtohwr) (0x0000FF), PG_LGOP_NONE); VID(update) (magic_cursor_display(),0,0,lxres,lyres); } return; case PGKEY_p: /* CTRL-ALT-p shows all loaded bitmaps */ { struct debug_bitmaps_data data; s16 lxres,lyres; VID(bitmap_getsize)(VID(window_debug)(), &lxres, &lyres); memset(&data,0,sizeof(data)); guru("Table of loaded bitmaps:"); handle_iterate(PG_TYPE_BITMAP,&debug_bitmaps,&data); VID(update) (VID(window_debug)(),0,0,lxres,lyres); } return; case PGKEY_o: /* CTRL-ALT-o traces all divnodes */ { s16 lxres,lyres; VID(bitmap_getsize)(magic_cursor_display(), &lxres, &lyres); r_divnode_trace(dts->top->head); VID(update) (magic_cursor_display(),0,0,lxres,lyres); } return; case PGKEY_a: /* CTRL-ALT-a shows application info */ { struct app_info *a; const struct pgstring *name; for (a=applist;a;a=a->next) { if (iserror(rdhandle((void**)&name,PG_TYPE_PGSTRING,-1,a->name))) name = pgstring_tmpwrap("(error reading handle)"); printf("app: '"); pgstring_print(name); printf("' type=%d owner=%d\n",a->type,a->owner); } } return; case PGKEY_r: /* CTRL-ALT-r draws the hotspot graph */ { struct hotspot *p; s16 lxres,lyres; VID(bitmap_getsize)(magic_cursor_display(), &lxres, &lyres); for (p=hotspotlist;p;p=p->next) hotspot_draw(p); VID(update) (magic_cursor_display(),0,0,lxres,lyres); } return; case PGKEY_i: /* CTRL-ALT-i gets video mode info */ { int x,y,celw,celh, pixelx,pixely; hwrcolor i, white, black, numcolors; s16 lxres,lyres; VID(bitmap_getsize)(VID(window_debug)(), &lxres, &lyres); guru("Video mode:\n" "Logical %dx%d, physical %dx%d, %d-bit color\n" "\n" "Color palette:\n", vid->lxres, vid->lyres, vid->xres, vid->yres, vid->bpp); if (vid->bpp <= 8) { /* Actual palette display */ i = 0; celw = (lxres-20) >> 4; celh = (lyres-70) >> 4; if (celw < celh) celh = celw; else celw = celh; white = VID(color_pgtohwr)(PGC_WHITE); black = VID(color_pgtohwr)(PGC_BLACK); numcolors = 1 << vid->bpp; for (y=0;y<16;y++) for (x=0;x<16 && i<numcolors;x++,i++) { pixelx = x*celw+10; pixely = y*celh+60; /* Display a rectangle of the color with black and white borders. * This is a lot like what the scribble app does, but we don't have * the convenience of a "frame" gropnode at this low level. */ VID(slab)(VID(window_debug)(),pixelx,pixely,celw,white,PG_LGOP_NONE); VID(slab)(VID(window_debug)(),pixelx,pixely+celh,celw,white,PG_LGOP_NONE); VID(bar)(VID(window_debug)(),pixelx,pixely,celh,white,PG_LGOP_NONE); VID(bar)(VID(window_debug)(),pixelx+celw,pixely,celh,white,PG_LGOP_NONE); VID(slab)(VID(window_debug)(),pixelx+1,pixely+1,celw-2, black, PG_LGOP_NONE); VID(slab)(VID(window_debug)(),pixelx+1,pixely-1+celh,celw-2, black, PG_LGOP_NONE); VID(bar)(VID(window_debug)(),pixelx+1,pixely+1,celh-2, black, PG_LGOP_NONE); VID(bar)(VID(window_debug)(),pixelx-1+celh,pixely+1,celh-2, black, PG_LGOP_NONE); VID(rect)(VID(window_debug)(),pixelx+2,pixely+2,celw-3,celh-3, i , PG_LGOP_NONE); } } else { /* Just some RGB gradients */ y = 60; VID(gradient)(VID(window_debug)(),10,y,lxres-20,20,0, 0x000000,0xFFFFFF, PG_LGOP_NONE); y += 30; VID(gradient)(VID(window_debug)(),10,y,lxres-20,20,0, 0x000000,0xFF0000, PG_LGOP_NONE); y += 30; VID(gradient)(VID(window_debug)(),10,y,lxres-20,20,0, 0x000000,0x00FF00, PG_LGOP_NONE); y += 30; VID(gradient)(VID(window_debug)(),10,y,lxres-20,20,0, 0x000000,0x0000FF, PG_LGOP_NONE); y += 30; } VID(update) (VID(window_debug)(),0,0,lxres,lyres); }