static int do_convert(int intype, const char* infile, int outtype, const char* outfile) { sign_key * key = NULL; const char * keytype = NULL; int ret = 1; key = import_read(infile, NULL, intype); if (!key) { fprintf(stderr, "Error reading key from '%s'\n", infile); goto out; } keytype = signkey_name_from_type(key->type, NULL); fprintf(stderr, "Key is a %s key\n", keytype); if (import_write(outfile, key, NULL, outtype) != 1) { fprintf(stderr, "Error writing key to '%s'\n", outfile); } else { fprintf(stderr, "Wrote key to '%s'\n", outfile); ret = 0; } out: if (key) { sign_key_free(key); } return ret; }
int signkey_generate(enum signkey_type keytype, int bits, const char* filename) { sign_key * key = NULL; buffer *buf = NULL; int ret = DROPBEAR_FAILURE; if (bits == 0) { bits = get_default_bits(keytype); } /* now we can generate the key */ key = new_sign_key(); seedrandom(); switch(keytype) { #ifdef DROPBEAR_RSA case DROPBEAR_SIGNKEY_RSA: key->rsakey = gen_rsa_priv_key(bits); break; #endif #ifdef DROPBEAR_DSS case DROPBEAR_SIGNKEY_DSS: key->dsskey = gen_dss_priv_key(bits); break; #endif #ifdef DROPBEAR_ECDSA case DROPBEAR_SIGNKEY_ECDSA_KEYGEN: case DROPBEAR_SIGNKEY_ECDSA_NISTP521: case DROPBEAR_SIGNKEY_ECDSA_NISTP384: case DROPBEAR_SIGNKEY_ECDSA_NISTP256: { ecc_key *ecckey = gen_ecdsa_priv_key(bits); keytype = ecdsa_signkey_type(ecckey); *signkey_key_ptr(key, keytype) = ecckey; } break; #endif default: dropbear_exit("Internal error"); } seedrandom(); buf = buf_new(MAX_PRIVKEY_SIZE); buf_put_priv_key(buf, key, keytype); sign_key_free(key); key = NULL; buf_setpos(buf, 0); ret = buf_writefile(buf, filename); buf_burn(buf); buf_free(buf); buf = NULL; return ret; }
/* Handle a diffie-hellman key exchange reply. */ void recv_msg_kexdh_reply() { DEF_MP_INT(dh_f); sign_key *hostkey = NULL; unsigned int type, keybloblen; unsigned char* keyblob = NULL; TRACE(("enter recv_msg_kexdh_reply")) if (cli_ses.kex_state != KEXDH_INIT_SENT) { dropbear_exit("Received out-of-order kexdhreply"); } m_mp_init(&dh_f); type = ses.newkeys->algo_hostkey; TRACE(("type is %d", type)) hostkey = new_sign_key(); keybloblen = buf_getint(ses.payload); keyblob = buf_getptr(ses.payload, keybloblen); if (!ses.kexstate.donefirstkex) { /* Only makes sense the first time */ checkhostkey(keyblob, keybloblen); } if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) { TRACE(("failed getting pubkey")) dropbear_exit("Bad KEX packet"); } if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) { TRACE(("failed getting mpint")) dropbear_exit("Bad KEX packet"); } kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey); mp_clear(&dh_f); mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL); m_free(cli_ses.dh_e); m_free(cli_ses.dh_x); if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) != DROPBEAR_SUCCESS) { dropbear_exit("Bad hostkey signature"); } sign_key_free(hostkey); hostkey = NULL; send_msg_newkeys(); ses.requirenext = SSH_MSG_NEWKEYS; TRACE(("leave recv_msg_kexdh_init")) }
void freerunopts(runopts* opts) { if (!opts) { return; } if (opts->hostkey) { sign_key_free(opts->hostkey); opts->hostkey = NULL; } m_free(opts->ports); m_free(opts); }
/* failure exit - format must be <= 100 chars */ void svr_dropbear_exit(int exitcode, const char* format, va_list param) { char fmtbuf[300]; int i; if (!sessinitdone) { /* before session init */ snprintf(fmtbuf, sizeof(fmtbuf), "Early exit: %s", format); } else if (ses.authstate.authdone) { /* user has authenticated */ snprintf(fmtbuf, sizeof(fmtbuf), "Exit (%s): %s", ses.authstate.pw_name, format); } else if (ses.authstate.pw_name) { /* we have a potential user */ snprintf(fmtbuf, sizeof(fmtbuf), "Exit before auth (user '%s', %d fails): %s", ses.authstate.pw_name, ses.authstate.failcount, format); } else { /* before userauth */ snprintf(fmtbuf, sizeof(fmtbuf), "Exit before auth: %s", format); } _dropbear_log(LOG_INFO, fmtbuf, param); #ifdef USE_VFORK /* For uclinux only the main server process should cleanup - we don't want * forked children doing that */ if (svr_ses.server_pid == getpid()) #endif { /* must be after we've done with username etc */ session_cleanup(); } if (svr_opts.hostkey) { sign_key_free(svr_opts.hostkey); svr_opts.hostkey = NULL; } for (i = 0; i < DROPBEAR_MAX_PORTS; i++) { m_free(svr_opts.addresses[i]); m_free(svr_opts.ports[i]); } exit(exitcode); }
/* Must be called after syslog/etc is working */ static void loadhostkey(const char *keyfile, int fatal_duplicate) { sign_key * read_key = new_sign_key(); enum signkey_type type = DROPBEAR_SIGNKEY_ANY; if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) { if (!svr_opts.delay_hostkey) { dropbear_log(LOG_WARNING, "Failed loading %s", keyfile); } } #ifdef DROPBEAR_RSA if (type == DROPBEAR_SIGNKEY_RSA) { loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate); } #endif #ifdef DROPBEAR_DSS if (type == DROPBEAR_SIGNKEY_DSS) { loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate); } #endif #ifdef DROPBEAR_ECDSA #ifdef DROPBEAR_ECC_256 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) { loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate); } #endif #ifdef DROPBEAR_ECC_384 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) { loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate); } #endif #ifdef DROPBEAR_ECC_521 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate); } #endif #endif /* DROPBEAR_ECDSA */ sign_key_free(read_key); TRACE(("leave loadhostkey")) }
static int do_convert(int intype, const char* infile, int outtype, const char* outfile) { sign_key * key = NULL; char * keytype = NULL; int ret = 1; key = import_read(infile, NULL, intype); if (!key) { fprintf(stderr, "Error reading key from '%s'\n", infile); goto out; } #ifdef DROPBEAR_RSA if (key->rsakey != NULL) { keytype = "RSA"; } #endif #ifdef DROPBEAR_DSS if (key->dsskey != NULL) { keytype = "DSS"; } #endif fprintf(stderr, "Key is a %s key\n", keytype); if (import_write(outfile, key, NULL, outtype) != 1) { fprintf(stderr, "Error writing key to '%s'\n", outfile); } else { fprintf(stderr, "Wrote key to '%s'\n", outfile); ret = 0; } out: if (key) { sign_key_free(key); } return ret; }
static int printpubfile(const char* filename) { buffer *buf = NULL; sign_key *key = NULL; enum signkey_type keytype; int ret; int err = DROPBEAR_FAILURE; buf = buf_new(MAX_PRIVKEY_SIZE); ret = buf_readfile(buf, filename); if (ret != DROPBEAR_SUCCESS) { fprintf(stderr, "Failed reading '%s'\n", filename); goto out; } key = new_sign_key(); keytype = DROPBEAR_SIGNKEY_ANY; buf_setpos(buf, 0); ret = buf_get_priv_key(buf, key, &keytype); if (ret == DROPBEAR_FAILURE) { fprintf(stderr, "Bad key in '%s'\n", filename); goto out; } printpubkey(key, keytype); err = DROPBEAR_SUCCESS; out: buf_burn(buf); buf_free(buf); buf = NULL; if (key) { sign_key_free(key); key = NULL; } return err; }
/* Handle a diffie-hellman key exchange reply. */ void recv_msg_kexdh_reply() { sign_key *hostkey = NULL; unsigned int type, keybloblen; unsigned char* keyblob = NULL; TRACE(("enter recv_msg_kexdh_reply")) if (cli_ses.kex_state != KEXDH_INIT_SENT) { dropbear_exit("Received out-of-order kexdhreply"); } type = ses.newkeys->algo_hostkey; TRACE(("type is %d", type)) hostkey = new_sign_key(); keybloblen = buf_getint(ses.payload); keyblob = buf_getptr(ses.payload, keybloblen); if (!ses.kexstate.donefirstkex) { /* Only makes sense the first time */ checkhostkey(keyblob, keybloblen); } if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) { TRACE(("failed getting pubkey")) dropbear_exit("Bad KEX packet"); } switch (ses.newkeys->algo_kex->mode) { case DROPBEAR_KEX_NORMAL_DH: { DEF_MP_INT(dh_f); m_mp_init(&dh_f); if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) { TRACE(("failed getting mpint")) dropbear_exit("Bad KEX packet"); } kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey); mp_clear(&dh_f); } break; case DROPBEAR_KEX_ECDH: #ifdef DROPBEAR_ECDH { buffer *ecdh_qs = buf_getstringbuf(ses.payload); kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey); buf_free(ecdh_qs); } #endif break; #ifdef DROPBEAR_CURVE25519 case DROPBEAR_KEX_CURVE25519: { buffer *ecdh_qs = buf_getstringbuf(ses.payload); kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey); buf_free(ecdh_qs); } #endif break; } if (cli_ses.dh_param) { free_kexdh_param(cli_ses.dh_param); cli_ses.dh_param = NULL; } #ifdef DROPBEAR_ECDH if (cli_ses.ecdh_param) { free_kexecdh_param(cli_ses.ecdh_param); cli_ses.ecdh_param = NULL; } #endif #ifdef DROPBEAR_CURVE25519 if (cli_ses.curve25519_param) { free_kexcurve25519_param(cli_ses.curve25519_param); cli_ses.curve25519_param = NULL; } #endif cli_ses.param_kex_algo = NULL; if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) { dropbear_exit("Bad hostkey signature"); } sign_key_free(hostkey); hostkey = NULL; send_msg_newkeys(); ses.requirenext[0] = SSH_MSG_NEWKEYS; ses.requirenext[1] = 0; TRACE(("leave recv_msg_kexdh_init")) }
/* if skip_exist is set it will silently return if the key file exists */ int signkey_generate(enum signkey_type keytype, int bits, const char* filename, int skip_exist) { sign_key * key = NULL; buffer *buf = NULL; char *fn_temp = NULL; int ret = DROPBEAR_FAILURE; bits = signkey_generate_get_bits(keytype, bits); /* now we can generate the key */ key = new_sign_key(); seedrandom(); switch(keytype) { #if DROPBEAR_RSA case DROPBEAR_SIGNKEY_RSA: key->rsakey = gen_rsa_priv_key(bits); break; #endif #if DROPBEAR_DSS case DROPBEAR_SIGNKEY_DSS: key->dsskey = gen_dss_priv_key(bits); break; #endif #if DROPBEAR_ECDSA case DROPBEAR_SIGNKEY_ECDSA_KEYGEN: case DROPBEAR_SIGNKEY_ECDSA_NISTP521: case DROPBEAR_SIGNKEY_ECDSA_NISTP384: case DROPBEAR_SIGNKEY_ECDSA_NISTP256: { ecc_key *ecckey = gen_ecdsa_priv_key(bits); keytype = ecdsa_signkey_type(ecckey); *signkey_key_ptr(key, keytype) = ecckey; } break; #endif default: dropbear_exit("Internal error"); } seedrandom(); buf = buf_new(MAX_PRIVKEY_SIZE); buf_put_priv_key(buf, key, keytype); sign_key_free(key); key = NULL; buf_setpos(buf, 0); fn_temp = m_malloc(strlen(filename) + 30); snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid()); ret = buf_writefile(buf, fn_temp); if (ret == DROPBEAR_FAILURE) { goto out; } if (link(fn_temp, filename) < 0) { /* If generating keys on connection (skipexist) it's OK to get EEXIST - we probably just lost a race with another connection to generate the key */ if (!(skip_exist && errno == EEXIST)) { dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename, strerror(errno)); /* XXX fallback to non-atomic copy for some filesystems? */ ret = DROPBEAR_FAILURE; goto out; } } out: if (buf) { buf_burn(buf); buf_free(buf); } if (fn_temp) { unlink(fn_temp); m_free(fn_temp); } return ret; }
/* Clean up, drop to user privileges, set up the environment and execute * the command/shell. This function does not return. */ static void execchild(struct ChanSess *chansess) { // BRCM begin #ifndef SSHD_GENKEY char *argv[4]; char * usershell; char * baseshell; unsigned int i; /* wipe the hostkey */ sign_key_free(ses.opts->hostkey); /* overwrite the prng state */ seedrandom(); /* close file descriptors except stdin/stdout/stderr * Need to be sure FDs are closed here to avoid reading files as root */ for (i = 3; i < (unsigned int)ses.maxfd; i++) { if (m_close(i) == DROPBEAR_FAILURE) { dropbear_exit("Error closing file desc"); } } /* clear environment */ /* if we're debugging using valgrind etc, we need to keep the LD_PRELOAD * etc. This is hazardous, so should only be used for debugging. */ #ifndef DEBUG_KEEP_ENV #ifdef HAVE_CLEARENV clearenv(); #else /* don't HAVE_CLEARENV */ environ = (char**)m_malloc(ENV_SIZE * sizeof(char*)); environ[0] = NULL; #endif /* HAVE_CLEARENV */ #endif /* DEBUG_KEEP_ENV */ /* We can only change uid/gid as root ... */ if (getuid() == 0) { if ((setgid(ses.authstate.pw->pw_gid) < 0) || (initgroups(ses.authstate.pw->pw_name, ses.authstate.pw->pw_gid) < 0) || (setuid(ses.authstate.pw->pw_uid) < 0)) { dropbear_exit("error changing user"); } } else { /* ... but if the daemon is the same uid as the requested uid, we don't * need to */ /* XXX - there is a minor issue here, in that if there are multiple * usernames with the same uid, but differing groups, then the * differing groups won't be set (as with initgroups()). The solution * is for the sysadmin not to give out the UID twice */ if (getuid() != ses.authstate.pw->pw_uid) { dropbear_exit("couldn't change user as non-root"); } } /* set env vars */ addnewvar("USER", ses.authstate.pw->pw_name); addnewvar("LOGNAME", ses.authstate.pw->pw_name); addnewvar("HOME", ses.authstate.pw->pw_dir); addnewvar("SHELL", ses.authstate.pw->pw_shell); // BRCM next line dd this to have /sbin path addnewvar("PATH", "/bin:/sbin:/usr/bin"); if (chansess->term != NULL) { addnewvar("TERM", chansess->term); } /* change directory */ if (chdir(ses.authstate.pw->pw_dir) < 0) { dropbear_exit("error changing directory"); } #ifndef DISABLE_X11FWD /* set up X11 forwarding if enabled */ x11setauth(chansess); #endif #ifndef DISABLE_AGENTFWD /* set up agent env variable */ agentset(chansess); #endif /* an empty shell should be interpreted as "/bin/sh" */ if (ses.authstate.pw->pw_shell[0] == '\0') { usershell = "/bin/sh"; } else { usershell = ses.authstate.pw->pw_shell; } baseshell = basename(usershell); if (chansess->cmd != NULL) { argv[0] = baseshell; } else { /* a login shell should be "-bash" for "/bin/bash" etc */ argv[0] = (char*)m_malloc(strlen(baseshell) + 2); /* 2 for "-" */ strcpy(argv[0], "-"); strcat(argv[0], baseshell); } if (chansess->cmd != NULL) { argv[1] = "-c"; argv[2] = chansess->cmd; argv[3] = NULL; } else { /* construct a shell of the form "-bash" etc */ argv[1] = NULL; } // BRCM begin: // execv(ses.authstate.pw->pw_shell, argv); // printf("BCM96345 ADSL Router\n"); BcmCli_run(CLI_ACCESS_REMOTE_SSH); exit(0); // BRCM end /* only reached on error */ dropbear_exit("child failed"); #endif // BRCM end ifudef SSHD_GENKEY }