/* * make_add - stick a single add onto the queue */ static void make_add(int modifier, KeySym keysym) { union op *uop; struct op_addmodifier *opam; uop = AllocStruct (union op); if (!uop) { badmsg ("attempt to allocate %ld byte addmodifier opcode", (long) sizeof (struct op_addmodifier)); return; } opam = &uop->addmodifier; opam->type = doAddModifier; opam->modifier = modifier; opam->count = 1; opam->keysyms = (KeySym *) malloc (sizeof (KeySym)); if (!opam->keysyms) { badmsg ("attempt to allocate %ld byte KeySym", (long) sizeof (KeySym)); free ((char *) opam); return; } opam->keysyms[0] = keysym; add_to_work_queue (uop); return; }
/* * make_remove - stick a single remove onto the queue */ static void make_remove(int modifier, KeyCode keycode) { union op *uop; struct op_removemodifier *oprm; uop = AllocStruct (union op); if (!uop) { badmsg ("attempt to allocate %ld byte removemodifier opcode", (long) sizeof (struct op_removemodifier)); return; } oprm = &uop->removemodifier; oprm->type = doRemoveModifier; oprm->modifier = modifier; oprm->count = 1; oprm->keycodes = (KeyCode *) malloc (sizeof (KeyCode)); if (!oprm->keycodes) { badmsg ("attempt to allocate %ld byte KeyCode", (long) sizeof (KeyCode)); free ((char *) oprm); return; } oprm->keycodes[0] = keycode; add_to_work_queue (uop); return; }
static void do_add(char *line, int len) { int n; int modifier; KeySym *kslist; union op *uop; struct op_addmodifier *opam; if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ badmsg0 ("add modifier input line"); return; } n = skip_chars (line, len); if (n < 1) { badmsg ("add modifier name %s", line); return; } modifier = parse_modifier (line, n); if (modifier < 0) { badmsgn ("add modifier name '%s', not allowed", line, n); return; } line += n, len -= n; n = skip_until_char (line, len, '='); if (n < 0) { badmsg0 ("add modifier = keysym"); return; } n++; /* skip = */ n += skip_space (line+n, len-n); line += n, len -= n; if (get_keysym_list (line, len, &n, &kslist) < 0) return; if (n == 0) { badmsg0 ("add modifier keysym list (empty)"); return; } uop = AllocStruct (union op); if (!uop) { badmsg ("attempt to allocate %ld byte addmodifier opcode", (long) sizeof (struct op_addmodifier)); return; } opam = &uop->addmodifier; opam->type = doAddModifier; opam->modifier = modifier; opam->count = n; opam->keysyms = kslist; add_to_work_queue (uop); }
static int authtisfn(Conn *c) { int fd, n; char *chal, resp[256]; Msg *m; if(!c->interactive) return -1; debug(DBG_AUTH, "try TIS\n"); sendmsg(allocmsg(c, SSH_CMSG_AUTH_TIS, 0)); m = recvmsg(c, -1); switch(m->type){ default: badmsg(m, SSH_SMSG_AUTH_TIS_CHALLENGE); case SSH_SMSG_FAILURE: free(m); return -1; case SSH_SMSG_AUTH_TIS_CHALLENGE: break; } chal = getstring(m); free(m); if((fd = open("/dev/cons", ORDWR)) < 0) error("can't open console"); fprint(fd, "TIS Authentication\n%s", chal); n = read(fd, resp, sizeof resp-1); if(n < 0) resp[0] = '\0'; else resp[n] = '\0'; if(resp[0] == 0 || resp[0] == '\n') return -1; m = allocmsg(c, SSH_CMSG_AUTH_TIS_RESPONSE, 4+strlen(resp)); putstring(m, resp); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ default: badmsg(m, 0); case SSH_SMSG_SUCCESS: free(m); return 0; case SSH_SMSG_FAILURE: free(m); return -1; } }
void handle_line(char *line, /* string to parse */ int len) /* length of line */ { int n; struct dt *dtp; n = skip_chars (line, len); if (n < 0) { badmsg ("input line '%s'", line); return; } for (dtp = dispatch_table; dtp->command != NULL; dtp++) { if (n == dtp->length && strncmp (line, dtp->command, dtp->length) == 0) { n += skip_space (line+n, len-n); line += n, len -= n; (*(dtp->proc)) (line, len); return; } } fprintf (stderr, "%s: unknown command on line %s:%d\n", ProgramName, inputFilename, lineno+1); parse_errors++; }
static int authpasswordfn(Conn *c) { Msg *m; UserPasswd *up; up = auth_getuserpasswd(c->interactive ? auth_getkey : nil, "proto=pass service=ssh server=%q user=%q", c->host, c->user); if(up == nil){ debug(DBG_AUTH, "getuserpasswd returned nothing (interactive=%d)\n", c->interactive); return -1; } debug(DBG_AUTH, "try using password from factotum\n"); m = allocmsg(c, SSH_CMSG_AUTH_PASSWORD, 4+strlen(up->passwd)); putstring(m, up->passwd); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ default: badmsg(m, 0); case SSH_SMSG_SUCCESS: free(m); return 0; case SSH_SMSG_FAILURE: free(m); return -1; } }
static int authuser(Conn *c) { int i; Msg *m; m = allocmsg(c, SSH_CMSG_USER, 4+strlen(c->user)); putstring(m, c->user); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_SUCCESS: free(m); return 0; case SSH_SMSG_FAILURE: free(m); break; default: badmsg(m, 0); } for(i=0; i<c->nokauth; i++){ debug(DBG_AUTH, "authmask %#lux, consider %s (%#x)\n", c->authmask, c->okauth[i]->name, 1<<c->okauth[i]->id); if(c->authmask & (1<<c->okauth[i]->id)) if((*c->okauth[i]->fn)(c) == 0) return 0; } debug(DBG_AUTH, "no auth methods worked; (authmask=%#lux)\n", c->authmask); return -1; }
int startagent(Conn *c) { int ret; Msg *m; m = allocmsg(c, SSH_CMSG_AGENT_REQUEST_FORWARDING, 0); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_SUCCESS: debug(DBG_AUTH, "agent allocated\n"); ret = 0; break; case SSH_SMSG_FAILURE: debug(DBG_AUTH, "agent failed to allocate\n"); ret = -1; break; default: badmsg(m, 0); ret = -1; break; } free(m); return ret; }
static void do_keysym(char *line, int len) { int n; KeyCode *keycodes; KeySym keysym; char *tmpname; if (len < 3 || !line || *line == '\0') { /* a=b minimum */ badmsg0 ("keysym input line"); return; } n = skip_chars (line, len); if (n < 1) { badmsg0 ("target keysym name"); return; } if (!parse_keysym(line, n, &tmpname, &keysym)) { badmsg ("keysym target key symbol '%s'", tmpname); return; } keycodes = KeysymToKeycodes (dpy, keysym, &n); if (n == 0) { badmsg ("keysym target keysym '%s', no corresponding keycodes", tmpname); return; } if (verbose) { int i; printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", tmpname, (long) keysym); for (i = 0; i < n; i++) printf (" 0x%x", keycodes[i]); printf("\n"); } finish_keycodes (line, len, keycodes, n); }
static void authsrvuser(Conn *c) { int i; char *ns, *user; AuthInfo *ai; Msg *m; m = recvmsg(c, SSH_CMSG_USER); user = getstring(m); c->user = emalloc(strlen(user)+1); strcpy(c->user, user); free(m); ai = authusername(c); while(ai == nil){ /* * clumsy: if the client aborted the auth_tis early * we don't send a new failure. we check this by * looking at c->unget, which is only used in that * case. */ if(c->unget != nil) goto skipfailure; sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0)); skipfailure: m = recvmsg(c, -1); for(i=0; i<c->nokauthsrv; i++) if(c->okauthsrv[i]->firstmsg == m->type){ ai = (*c->okauthsrv[i]->fn)(c, m); break; } if(i==c->nokauthsrv) badmsg(m, 0); } sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0)); if(noworld(ai->cuid)) ns = "/lib/namespace.noworld"; else ns = nil; if(auth_chuid(ai, ns) < 0){ sshlog("auth_chuid to %s: %r", ai->cuid); sysfatal("auth_chuid: %r"); } sshlog("logged in as %s", ai->cuid); auth_freeAI(ai); }
static void finish_keycodes(const char *line, int len, KeyCode *keycodes, int count) { int n; KeySym *kslist; union op *uop; struct op_keycode *opk; n = skip_until_char (line, len, '='); line += n, len -= n; if (len < 1 || *line != '=') { /* = minimum */ badmsg0 ("keycode command (missing keysym list),"); return; } line++, len--; /* skip past the = */ n = skip_space (line, len); line += n, len -= n; /* allow empty list */ if (get_keysym_list (line, len, &n, &kslist) < 0) return; while (--count >= 0) { uop = AllocStruct (union op); if (!uop) { badmsg ("attempt to allocate a %ld byte keycode opcode", (long) sizeof (struct op_keycode)); return; } opk = &uop->keycode; opk->type = doKeycode; opk->target_keycode = keycodes[count]; opk->count = n; opk->keysyms = kslist; add_to_work_queue (uop); } #ifdef later /* make sure we handle any special keys */ check_special_keys (keycode, n, kslist); #endif }
static void do_clear(char *line, int len) { int n; int modifier; union op *uop; struct op_clearmodifier *opcm; if (len < 4 || !line || *line == '\0') { /* Lock minimum */ badmsg0 ("clear modifier input line"); return; } n = skip_chars (line, len); modifier = parse_modifier (line, n); if (modifier < 0) { badmsgn ("clear modifier name '%s'", line, n); return; } n += skip_space (line+n, len-n); if (n != len) { badmsgn ("extra argument '%s' to clear modifier", line+n, len-n); /* okay to continue */ } uop = AllocStruct (union op); if (!uop) { badmsg ("attempt to allocate %ld byte clearmodifier opcode", (long) sizeof (struct op_clearmodifier)); return; } opcm = &uop->clearmodifier; opcm->type = doClearModifier; opcm->modifier = modifier; add_to_work_queue (uop); }
void requestpty(Conn *c) { char *term; int nrow, ncol, width, height; Msg *m; m = allocmsg(c, SSH_CMSG_REQUEST_PTY, 1024); if((term = getenv("TERM")) == nil) term = "9term"; putstring(m, term); readgeom(&nrow, &ncol, &width, &height); putlong(m, nrow); /* characters */ putlong(m, ncol); putlong(m, width); /* pixels */ putlong(m, height); if(rawhack) putbytes(m, rawptyopt, sizeof rawptyopt); else putbytes(m, ptyopt, sizeof ptyopt); sendmsg(m); m = recvmsg(c, 0); switch(m->type){ case SSH_SMSG_SUCCESS: debug(DBG_IO, "PTY allocated\n"); break; case SSH_SMSG_FAILURE: debug(DBG_IO, "PTY allocation failed\n"); break; default: badmsg(m, 0); } free(m); }
static int get_keysym_list(const char *line, int len, int *np, KeySym **kslistp) { int havesofar, maxcanhave; KeySym *keysymlist; *np = 0; *kslistp = NULL; if (len == 0) return (0); /* empty list */ havesofar = 0; maxcanhave = 4; /* most lists are small */ keysymlist = (KeySym *) malloc (maxcanhave * sizeof (KeySym)); if (!keysymlist) { badmsg ("attempt to allocate %ld byte initial keysymlist", (long) (maxcanhave * sizeof (KeySym))); return (-1); } while (len > 0) { KeySym keysym; int n; char *tmpname; Bool ok; n = skip_space (line, len); line += n, len -= n; n = skip_chars (line, len); if (n < 0) { badmsg0 ("keysym name list"); free(keysymlist); return (-1); } ok = parse_keysym (line, n, &tmpname, &keysym); line += n, len -= n; if (!ok) { badmsg ("keysym name '%s' in keysym list", tmpname); /* do NOT return here, look for others */ continue; } /* * Do NOT test to see if the keysym translates to a keycode or you * won't be able to assign new ones.... */ /* grow the list bigger if necessary */ if (havesofar >= maxcanhave) { KeySym *origkeysymlist = keysymlist; maxcanhave *= 2; keysymlist = (KeySym *) realloc (keysymlist, maxcanhave * sizeof (KeySym)); if (!keysymlist) { badmsg ("attempt to grow keysym list to %ld bytes", (long) (maxcanhave * sizeof (KeySym))); free(origkeysymlist); return (-1); } } /* and add it to the list */ keysymlist[havesofar++] = keysym; } *kslistp = keysymlist; *np = havesofar; return (0); }
static int authrsafn(Conn *c) { uint8_t chalbuf[32+SESSIDLEN], response[MD5dlen]; char *s, *p; int afd, ret; AuthRpc *rpc; Msg *m; mpint *chal, *decr, *unpad, *mod; debug(DBG_AUTH, "rsa!\n"); if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n"); return -1; } if((rpc = auth_allocrpc(afd)) == nil){ debug(DBG_AUTH, "auth_allocrpc: %r\n"); close(afd); return -1; } s = "proto=rsa role=client"; if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){ debug(DBG_AUTH, "auth_rpc start %s failed: %r\n", s); auth_freerpc(rpc); close(afd); return -1; } ret = -1; debug(DBG_AUTH, "trying factotum rsa keys\n"); while(auth_rpc(rpc, "read", nil, 0) == ARok){ debug(DBG_AUTH, "try %s\n", (char*)rpc->arg); mod = strtomp(rpc->arg, nil, 16, nil); m = allocmsg(c, SSH_CMSG_AUTH_RSA, 16+(mpsignif(mod)+7/8)); putmpint(m, mod); sendmsg(m); mpfree(mod); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_FAILURE: debug(DBG_AUTH, "\tnot accepted %s\n", (char*)rpc->arg); free(m); continue; default: badmsg(m, 0); case SSH_SMSG_AUTH_RSA_CHALLENGE: break; } chal = getmpint(m); debug(DBG_AUTH, "\tgot challenge %B\n", chal); free(m); p = mptoa(chal, 16, nil, 0); mpfree(chal); if(p == nil){ debug(DBG_AUTH, "\tmptoa failed: %r\n"); unpad = mpnew(0); goto Keepgoing; } if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){ debug(DBG_AUTH, "\tauth_rpc write failed: %r\n"); free(p); unpad = mpnew(0); /* it will fail, we'll go round again */ goto Keepgoing; } free(p); if(auth_rpc(rpc, "read", nil, 0) != ARok){ debug(DBG_AUTH, "\tauth_rpc read failed: %r\n"); unpad = mpnew(0); goto Keepgoing; } decr = strtomp(rpc->arg, nil, 16, nil); debug(DBG_AUTH, "\tdecrypted %B\n", decr); unpad = rsaunpad(decr); debug(DBG_AUTH, "\tunpadded %B\n", unpad); mpfree(decr); Keepgoing: mptoberjust(unpad, chalbuf, 32); mpfree(unpad); debug(DBG_AUTH, "\trjusted %.*H\n", 32, chalbuf); memmove(chalbuf+32, c->sessid, SESSIDLEN); debug(DBG_AUTH, "\tappend sesskey %.*H\n", 32, chalbuf); md5(chalbuf, 32+SESSIDLEN, response, nil); m = allocmsg(c, SSH_CMSG_AUTH_RSA_RESPONSE, MD5dlen); putbytes(m, response, MD5dlen); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_FAILURE: free(m); continue; default: badmsg(m, 0); case SSH_SMSG_SUCCESS: break; } ret = 0; break; } auth_freerpc(rpc); close(afd); return ret; }
void fromnet(Conn *c) { int infd, kidpid, n; char *cmd; Msg *m; infd = kidpid = -1; for(;;){ m = recvmsg(c, -1); if(m == nil) exits(nil); switch(m->type){ default: //badmsg(m, 0); sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0)); break; case SSH_MSG_DISCONNECT: sysfatal("client disconnected"); case SSH_CMSG_REQUEST_PTY: sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0)); break; case SSH_CMSG_X11_REQUEST_FORWARDING: sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0)); break; case SSH_CMSG_MAX_PACKET_SIZE: maxmsg = getlong(m); sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0)); break; case SSH_CMSG_REQUEST_COMPRESSION: sendmsg(allocmsg(c, SSH_SMSG_FAILURE, 0)); break; case SSH_CMSG_EXEC_SHELL: startcmd(c, nil, &kidpid, &infd); goto InteractiveMode; case SSH_CMSG_EXEC_CMD: cmd = getstring(m); startcmd(c, cmd, &kidpid, &infd); goto InteractiveMode; } free(m); } InteractiveMode: for(;;){ free(m); m = recvmsg(c, -1); if(m == nil) exits(nil); switch(m->type){ default: badmsg(m, 0); case SSH_MSG_DISCONNECT: postnote(PNGROUP, kidpid, "hangup"); sysfatal("client disconnected"); case SSH_CMSG_STDIN_DATA: if(infd != 0){ n = getlong(m); write(infd, getbytes(m, n), n); } break; case SSH_CMSG_EOF: close(infd); infd = -1; break; case SSH_CMSG_EXIT_CONFIRMATION: /* sent by some clients as dying breath */ exits(nil); case SSH_CMSG_WINDOW_SIZE: /* we don't care */ break; } } }
void fromnet(Conn *c) { int fd, len; char *s, *es, *r, *w; uint32_t ex; char buf[64]; Msg *m; for(;;){ m = recvmsg(c, -1); if(m == nil) break; switch(m->type){ default: badmsg(m, 0); case SSH_SMSG_EXITSTATUS: ex = getlong(m); if(ex==0) exits(0); sprint(buf, "%lu", ex); exits(buf); case SSH_MSG_DISCONNECT: s = getstring(m); error("disconnect: %s", s); /* * If we ever add reverse port forwarding, we'll have to * revisit this. It assumes that the agent connections are * the only ones. */ case SSH_SMSG_AGENT_OPEN: if(!forwardagent) error("server tried to use agent forwarding"); handleagentopen(m); break; case SSH_MSG_CHANNEL_INPUT_EOF: if(!forwardagent) error("server tried to use agent forwarding"); handleagentieof(m); break; case SSH_MSG_CHANNEL_OUTPUT_CLOSED: if(!forwardagent) error("server tried to use agent forwarding"); handleagentoclose(m); break; case SSH_MSG_CHANNEL_DATA: if(!forwardagent) error("server tried to use agent forwarding"); handleagentmsg(m); break; case SSH_SMSG_STDOUT_DATA: fd = outfd; goto Dataout; case SSH_SMSG_STDERR_DATA: fd = 2; goto Dataout; Dataout: len = getlong(m); s = (char*)getbytes(m, len); if(crstrip){ es = s+len; for(r=w=s; r<es; r++) if(*r != '\r') *w++ = *r; len = w-s; } write(fd, s, len); break; } free(m); } }
static void do_pointer(char *line, int len) { int n; int i; unsigned long val; union op *uop; struct op_pointer *opp; unsigned char buttons[MAXBUTTONCODES]; int nbuttons; char *strval; Bool ok; if (len < 2 || !line || *line == '\0') { /* =1 minimum */ badmsg0 ("buttons input line"); return; } nbuttons = XGetPointerMapping (dpy, buttons, MAXBUTTONCODES); n = skip_space (line, len); line += n, len -= n; if (line[0] != '=') { badmsg0 ("buttons pointer code list, missing equal sign"); return; } line++, len--; /* skip = */ n = skip_space (line, len); line += n, len -= n; i = 0; if (len < 7 || strncasecmp (line, "default", 7) != 0) { while (len > 0) { n = skip_space (line, len); line += n, len -= n; if (line[0] == '\0') break; n = skip_word (line, len); if (n < 1) { badmsg ("skip of word in buttons line: %s", line); return; } strval = copy_to_scratch(line, n); ok = parse_number (strval, &val); if (!ok || val >= MAXBUTTONCODES) { badmsg ("value %s given for buttons list", strval); return; } buttons[i++] = (unsigned char) val; line += n, len -= n; } } if (i > 0 && i != nbuttons) { fprintf (stderr, "Warning: Only changing the first %d of %d buttons.\n", i, nbuttons); i = nbuttons; } uop = AllocStruct (union op); if (!uop) { badmsg ("attempt to allocate a %ld byte pointer opcode", (long) sizeof (struct op_pointer)); return; } opp = &uop->pointer; opp->type = doPointer; opp->count = i; for (i = 0; i < opp->count; i++) { opp->button_codes[i] = buttons[i]; } add_to_work_queue (uop); }
static void do_remove(char *line, int len) { int n; int nc; int i; int tot; int modifier; KeySym *kslist; KeyCode *kclist; union op *uop; struct op_removemodifier *oprm; if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ badmsg0 ("remove modifier input line"); return; } n = skip_chars (line, len); if (n < 1) { badmsg ("remove modifier name %s", line); return; } modifier = parse_modifier (line, n); if (modifier < 0) { badmsgn ("remove modifier name '%s', not allowed", line, n); return; } line += n, len -= n; n = skip_until_char (line, len, '='); if (n < 0) { badmsg0 ("remove modifier = keysym"); return; } n++; n += skip_space (line+n, len-n); line += n, len -= n; if (get_keysym_list (line, len, &n, &kslist) < 0) return; if (n == 0) { badmsg0 ("remove modifier keysym list (empty)"); return; } /* * unlike the add command, we have to now evaluate the keysyms */ kclist = (KeyCode *) malloc (n * sizeof (KeyCode)); if (!kclist) { badmsg ("attempt to allocate %ld byte keycode list", (long) (n * sizeof (KeyCode))); free ((char *) kslist); return; } tot = n; nc = 0; for (i = 0; i < n; i++) { int num_kcs; KeyCode *kcs; kcs = KeysymToKeycodes (dpy, kslist[i], &num_kcs); if (num_kcs == 0) { char *tmpname = XKeysymToString (kslist[i]); badmsg ("keysym in remove modifier list '%s', no corresponding keycodes", tmpname ? tmpname : "?"); continue; } if (verbose) { int j; char *tmpname = XKeysymToString (kslist[i]); printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", tmpname ? tmpname : "?", (long) kslist[i]); for (j = 0; j < num_kcs; j++) printf(" 0x%x", kcs[j]); printf("\n"); } if (nc + num_kcs > tot) { tot = nc + num_kcs; kclist = (KeyCode *)realloc((char *)kclist, tot * sizeof(KeyCode)); if (!kclist) { badmsg ("attempt to allocate %ld byte keycode list", (long) (tot * sizeof (KeyCode))); free ((char *) kslist); return; } } while (--num_kcs >= 0) kclist[nc++] = *kcs++; /* okay, add it to list */ } free ((char *) kslist); /* all done with it */ uop = AllocStruct (union op); if (!uop) { badmsg ("attempt to allocate %ld byte removemodifier opcode", (long) sizeof (struct op_removemodifier)); return; } oprm = &uop->removemodifier; oprm->type = doRemoveModifier; oprm->modifier = modifier; oprm->count = nc; oprm->keycodes = kclist; add_to_work_queue (uop); }