/* Generates a random mp_int. * max is a *mp_int specifying an upper bound. * rand must be an initialised *mp_int for the result. * the result rand satisfies: 0 < rand < max * */ void gen_random_mpint(mp_int *max, mp_int *rand) { unsigned char *randbuf = NULL; unsigned int len = 0; const unsigned char masks[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f}; const int size_bits = mp_count_bits(max); len = size_bits / 8; if ((size_bits % 8) != 0) { len += 1; } randbuf = (unsigned char*)m_malloc(len); do { genrandom(randbuf, len); /* Mask out the unrequired bits - mp_read_unsigned_bin expects * MSB first.*/ randbuf[0] &= masks[size_bits % 8]; bytes_to_mp(rand, randbuf, len); /* keep regenerating until we get one satisfying * 0 < rand < max */ } while (!(mp_cmp(rand, max) == MP_LT && mp_cmp_d(rand, 0) == MP_GT)); m_burn(randbuf, len); m_free(randbuf); }
static unsigned char* get_response(unsigned char* prompt) { FILE* tty = NULL; unsigned char* response = NULL; /* not a password, but a reasonable limit */ char buf[DROPBEAR_MAX_CLI_PASS]; char* ret = NULL; fprintf(stderr, "%s", prompt); tty = fopen(_PATH_TTY, "r"); if (tty) { ret = fgets(buf, sizeof(buf), tty); fclose(tty); } else { ret = fgets(buf, sizeof(buf), stdin); } if (ret == NULL) { response = (unsigned char*)m_strdup(""); } else { unsigned int buflen = strlen(buf); /* fgets includes newlines */ if (buflen > 0 && buf[buflen-1] == '\n') buf[buflen-1] = '\0'; response = (unsigned char*)m_strdup(buf); } m_burn(buf, sizeof(buf)); return response; }
/* return len bytes of pseudo-random data */ void genrandom(unsigned char* buf, unsigned int len) { hash_state hs; unsigned char hash[SHA1_HASH_SIZE]; unsigned int copylen; if (!donerandinit) { dropbear_exit("seedrandom not done"); } while (len > 0) { sha1_init(&hs); sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); sha1_process(&hs, (void*)&counter, sizeof(counter)); sha1_done(&hs, hash); counter++; if (counter > MAX_COUNTER) { seedrandom(); } copylen = MIN(len, SHA1_HASH_SIZE); memcpy(buf, hash, copylen); len -= copylen; buf += copylen; } m_burn(hash, sizeof(hash)); }
static void getp(dss_key *key, unsigned int size) { DEF_MP_INT(tempX); DEF_MP_INT(tempC); DEF_MP_INT(tempP); DEF_MP_INT(temp2q); int result; unsigned char *buf; m_mp_init_multi(&tempX, &tempC, &tempP, &temp2q, NULL); /* 2*q */ if (mp_mul_d(key->q, 2, &temp2q) != MP_OKAY) { fprintf(stderr, "dss key generation failed\n"); exit(1); } buf = (unsigned char*)m_malloc(size); result = 0; do { genrandom(buf, size); buf[0] |= 0x80; /* set the top bit high */ /* X is a random mp_int */ bytes_to_mp(&tempX, buf, size); /* C = X mod 2q */ if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) { fprintf(stderr, "dss key generation failed\n"); exit(1); } /* P = X - (C - 1) = X - C + 1*/ if (mp_sub(&tempX, &tempC, &tempP) != MP_OKAY) { fprintf(stderr, "dss key generation failed\n"); exit(1); } if (mp_add_d(&tempP, 1, key->p) != MP_OKAY) { fprintf(stderr, "dss key generation failed\n"); exit(1); } /* now check for prime, 5 rounds is enough according to HAC */ /* result == 1 => p is prime */ if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) { fprintf(stderr, "dss key generation failed\n"); exit(1); } } while (!result); mp_clear_multi(&tempX, &tempC, &tempP, &temp2q, NULL); m_burn(buf, size); m_free(buf); }
/* Process a password auth request, sending success or failure messages as * appropriate */ void svr_auth_password() { char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */ char * testcrypt = NULL; /* crypt generated from the user's password sent */ unsigned char * password; unsigned int passwordlen; unsigned int changepw; passwdcrypt = ses.authstate.pw_passwd; #ifdef DEBUG_HACKCRYPT /* debugging crypt for non-root testing with shadows */ passwdcrypt = DEBUG_HACKCRYPT; #endif /* check if client wants to change password */ changepw = buf_getbool(ses.payload); if (changepw) { /* not implemented by this server */ send_msg_userauth_failure(0, 1); return; } password = buf_getstring(ses.payload, &passwordlen); /* the first bytes of passwdcrypt are the salt */ testcrypt = crypt((char*)password, passwdcrypt); m_burn(password, passwordlen); m_free(password); /* check for empty password */ if (passwdcrypt[0] == '\0') { dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected", ses.authstate.pw_name); send_msg_userauth_failure(0, 1); return; } if (strcmp(testcrypt, passwdcrypt) == 0) { /* successful authentication */ dropbear_log(LOG_NOTICE, "Password auth succeeded for '%s' from %s", ses.authstate.pw_name, svr_ses.addrstring); send_msg_userauth_success(); } else { dropbear_log(LOG_WARNING, "Bad password attempt for '%s' from %s", ses.authstate.pw_name, svr_ses.addrstring); send_msg_userauth_failure(0, 1); } }
/* clear one (frees) */ void mp_clear (mp_int * a) { /* only do anything if a hasn't been freed previously */ if (a->dp != NULL) { /* first zero the digits */ m_burn(a->dp, a->alloc * sizeof(*a->dp)); /* free ram */ XFREE(a->dp); /* reset members to make debugging easier */ a->dp = NULL; a->alloc = a->used = 0; a->sign = MP_ZPOS; } }
/* return a prime suitable for p or q */ static void getrsaprime(mp_int* prime, mp_int *primeminus, mp_int* rsa_e, unsigned int size_bytes) { unsigned char *buf; DEF_MP_INT(temp_gcd); buf = (unsigned char*)m_malloc(size_bytes); m_mp_init(&temp_gcd); do { /* generate a random odd number with MSB set, then find the the next prime above it */ genrandom(buf, size_bytes); buf[0] |= 0x80; bytes_to_mp(prime, buf, size_bytes); /* find the next integer which is prime, 8 round of miller-rabin */ if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) { fprintf(stderr, "RSA generation failed\n"); exit(1); } /* subtract one to get p-1 */ if (mp_sub_d(prime, 1, primeminus) != MP_OKAY) { fprintf(stderr, "RSA generation failed\n"); exit(1); } /* check relative primality to e */ if (mp_gcd(primeminus, rsa_e, &temp_gcd) != MP_OKAY) { fprintf(stderr, "RSA generation failed\n"); exit(1); } } while (mp_cmp_d(&temp_gcd, 1) != MP_EQ); /* while gcd(p-1, e) != 1 */ /* now we have a good value for result */ mp_clear(&temp_gcd); m_burn(buf, size_bytes); m_free(buf); }
/* initialise the prng from /dev/(u)random or prngd */ void seedrandom() { unsigned char readbuf[INIT_SEED_SIZE]; hash_state hs; /* initialise so that things won't warn about * hashing an undefined buffer */ if (!donerandinit) { m_burn(hashpool, sizeof(hashpool)); } /* get the seed data */ readrand(readbuf, sizeof(readbuf)); /* hash in the new seed data */ sha1_init(&hs); sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); sha1_process(&hs, (void*)readbuf, sizeof(readbuf)); sha1_done(&hs, hashpool); counter = 0; donerandinit = 1; }
/* Generate the actual encryption/integrity keys, using the results of the * key exchange, as specified in section 5.2 of the IETF secsh-transport * draft. This occurs after the DH key-exchange. * * ses.newkeys is the new set of keys which are generated, these are only * taken into use after both sides have sent a newkeys message */ static void gen_new_keys() { unsigned char IV[MAX_IV_LEN]; unsigned char key[MAX_KEY_LEN]; hash_state hs; unsigned int keysize; TRACE(("enter gen_new_keys")); /* the dh_K and hash are the start of all hashes, we make use of that */ sha1_init(&hs); sha1_process_mp(&hs, ses.dh_K); mp_clear(ses.dh_K); m_free(ses.dh_K); sha1_process(&hs, ses.hash, SHA1_HASH_SIZE); m_burn(ses.hash, SHA1_HASH_SIZE); /* client->server IV */ hashkeys(IV, SHA1_HASH_SIZE, &hs, 'A'); /* client->server encryption key */ keysize = ses.newkeys->recv_algo_crypt->keysize; hashkeys(key, keysize, &hs, 'C'); if (cbc_start( find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name), IV, key, keysize, 0, &ses.newkeys->recv_symmetric_struct) != CRYPT_OK) { dropbear_exit("crypto error"); } /* server->client IV */ hashkeys(IV, SHA1_HASH_SIZE, &hs, 'B'); /* server->client encryption key */ keysize = ses.newkeys->trans_algo_crypt->keysize; hashkeys(key, keysize, &hs, 'D'); if (cbc_start( find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name), IV, key, keysize, 0, &ses.newkeys->trans_symmetric_struct) != CRYPT_OK) { dropbear_exit("crypto error"); } /* MAC key client->server */ keysize = ses.newkeys->recv_algo_mac->keysize; hashkeys(ses.newkeys->recvmackey, keysize, &hs, 'E'); /* MAC key server->client */ keysize = ses.newkeys->trans_algo_mac->keysize; hashkeys(ses.newkeys->transmackey, keysize, &hs, 'F'); #ifndef DISABLE_ZLIB gen_new_zstreams(); #endif /* Switch over to the new keys */ m_burn(ses.keys, sizeof(struct key_context)); m_free(ses.keys); ses.keys = ses.newkeys; ses.newkeys = NULL; TRACE(("leave gen_new_keys")); }
/* overwrite the contents of the buffer to clear it */ void buf_burn(buffer* buf) { m_burn(buf->data, buf->size); }
void recv_msg_userauth_info_request() { unsigned char *name = NULL; unsigned char *instruction = NULL; unsigned int num_prompts = 0; unsigned int i; unsigned char *prompt = NULL; unsigned int echo = 0; unsigned char *response = NULL; TRACE(("enter recv_msg_recv_userauth_info_request")) /* Let the user know what password/host they are authing for */ if (!cli_ses.interact_request_received) { fprintf(stderr, "Login for %s@%s\n", cli_opts.username, //cli_opts.remotehost); cli_opts.remote_name_str); } cli_ses.interact_request_received = 1; name = buf_getstring(ses.payload, NULL); instruction = buf_getstring(ses.payload, NULL); /* language tag */ buf_eatstring(ses.payload); num_prompts = buf_getint(ses.payload); if (num_prompts >= DROPBEAR_MAX_CLI_INTERACT_PROMPTS) { dropbear_exit("Too many prompts received for keyboard-interactive"); } /* we'll build the response as we go */ CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_INFO_RESPONSE); buf_putint(ses.writepayload, num_prompts); if (strlen(name) > 0) { cleantext(name); fprintf(stderr, "%s", name); } m_free(name); if (strlen(instruction) > 0) { cleantext(instruction); fprintf(stderr, "%s", instruction); } m_free(instruction); for (i = 0; i < num_prompts; i++) { unsigned int response_len = 0; prompt = buf_getstring(ses.payload, NULL); cleantext(prompt); echo = buf_getbool(ses.payload); if (!echo) { unsigned char* p = getpass_or_cancel(prompt); response = m_strdup(p); m_burn(p, strlen(p)); } else { response = get_response(prompt); } response_len = strlen(response); buf_putstring(ses.writepayload, response, response_len); m_burn(response, response_len); m_free(response); } encrypt_packet(); TRACE(("leave recv_msg_recv_userauth_info_request")) }
/* Process a password auth request, sending success or failure messages as * appropriate */ void svr_auth_password() { //brcm begin #ifndef SSHD_GENKEY #ifdef HAVE_SHADOW_H struct spwd *spasswd = NULL; #endif char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */ char * testcrypt = NULL; /* crypt generated from the user's password sent */ unsigned char * password; unsigned int passwordlen; unsigned int changepw; // brcm add matched flag. int matched = 0; passwdcrypt = ses.authstate.pw->pw_passwd; #ifdef HAVE_SHADOW_H /* get the shadow password if possible */ spasswd = getspnam(ses.authstate.printableuser); if (spasswd != NULL && spasswd->sp_pwdp != NULL) { passwdcrypt = spasswd->sp_pwdp; } #endif #ifdef DEBUG_HACKCRYPT /* debugging crypt for non-root testing with shadows */ passwdcrypt = DEBUG_HACKCRYPT; #endif /* check for empty password - need to do this again here * since the shadow password may differ to that tested * in auth.c */ if (passwdcrypt[0] == '\0') { dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected", ses.authstate.printableuser); send_msg_userauth_failure(0, 1); return; } /* check if client wants to change password */ changepw = buf_getbool(ses.payload); if (changepw) { /* not implemented by this server */ send_msg_userauth_failure(0, 1); return; } password = buf_getstring(ses.payload, &passwordlen); /* the first bytes of passwdcrypt are the salt */ testcrypt = crypt((char*)password, passwdcrypt); // brcm add local/remote login check // We are doing all this auth checking inside sshd code instead of via proper CLI API. if ((glbAccessMode == NETWORK_ACCESS_LAN_SIDE && \ (!strcmp(ses.authstate.username, "user") || !strcmp(ses.authstate.username, "admin"))) || (glbAccessMode == NETWORK_ACCESS_WAN_SIDE && !strcmp(ses.authstate.username, "support"))) { matched = 1; strcpy(currUser, ses.authstate.username); if (!strcmp(currUser, "admin")) { currPerm = 0x80; /*PERM_ADMIN */ } else if (!strcmp(currUser, "support")) { currPerm = 0x40; /* PERM_SUPPORT */ } else if (!strcmp(currUser, "user")) { currPerm = 0x01; /* PERM_USER */ } } m_burn(password, passwordlen); m_free(password); if (strcmp(testcrypt, passwdcrypt) == 0 && matched) { /* successful authentication */ // brcm commented next msg //dropbear_log(LOG_NOTICE, // "password auth succeeded for '%s' from %s", // ses.authstate.printableuser, // svr_ses.addrstring); send_msg_userauth_success(); } else { #ifdef DESKTOP_LINUX dropbear_log(LOG_WARNING, "skip password auth for now, return success"); send_msg_userauth_success(); #else dropbear_log(LOG_WARNING, "bad password attempt for '%s' from %s", ses.authstate.printableuser, svr_ses.addrstring); send_msg_userauth_failure(0, 1); #endif } #endif // brcm end, ifndef SSHD_GENKEY }
void svr_getopts(int argc, char ** argv) { unsigned int i; char ** next = 0; int nextisport = 0; int nextignored = 0; char* recv_window_arg = NULL; char* keepalive_arg = NULL; char* idle_timeout_arg = NULL; char* master_password_arg = NULL; /* see printhelp() for options */ svr_opts.rsakeyfile = NULL; svr_opts.dsskeyfile = NULL; svr_opts.bannerfile = NULL; svr_opts.forcedhomepath = NULL; svr_opts.fake_permissions = 0; #ifdef ENABLE_SVR_MASTER_PASSWORD svr_opts.master_password = NULL; #endif svr_opts.banner = NULL; svr_opts.forkbg = 1; svr_opts.norootlogin = 0; svr_opts.noauthpass = 0; svr_opts.noauthpubkey = 0; svr_opts.norootpass = 0; svr_opts.inetdmode = 0; svr_opts.portcount = 0; svr_opts.hostkey = NULL; svr_opts.pidfile = DROPBEAR_PIDFILE; #ifdef ENABLE_SVR_LOCALTCPFWD svr_opts.nolocaltcp = 0; #endif #ifdef ENABLE_SVR_REMOTETCPFWD svr_opts.noremotetcp = 0; #endif #ifndef DISABLE_ZLIB opts.enable_compress = 1; #endif /* not yet opts.ipv4 = 1; opts.ipv6 = 1; */ #ifdef DO_MOTD svr_opts.domotd = 1; #endif #ifndef DISABLE_SYSLOG svr_opts.usingsyslog = 1; #endif opts.recv_window = DEFAULT_RECV_WINDOW; opts.keepalive_secs = DEFAULT_KEEPALIVE; opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT; #ifdef ENABLE_SVR_REMOTETCPFWD opts.listen_fwd_all = 0; #endif for (i = 1; i < (unsigned int)argc; i++) { if (nextisport) { addportandaddress(argv[i]); nextisport = 0; continue; } if (nextignored) { nextignored = 0; continue; } if (next) { *next = argv[i]; if (*next == NULL) { dropbear_exit("Invalid null argument"); } next = 0x00; continue; } if (argv[i][0] == '-') { switch (argv[i][1]) { case 'b': next = &svr_opts.bannerfile; break; case 'H': next = &svr_opts.forcedhomepath; break; #ifdef DROPBEAR_DSS case 'd': next = &svr_opts.dsskeyfile; break; #endif #ifdef DROPBEAR_RSA case 'r': next = &svr_opts.rsakeyfile; break; #endif case 'F': svr_opts.forkbg = 0; break; #ifndef DISABLE_SYSLOG case 'E': svr_opts.usingsyslog = 0; break; #endif #ifdef ENABLE_SVR_LOCALTCPFWD case 'j': svr_opts.nolocaltcp = 1; break; #endif #ifdef ENABLE_SVR_REMOTETCPFWD case 'k': svr_opts.noremotetcp = 1; break; case 'a': opts.listen_fwd_all = 1; break; #endif #ifdef INETD_MODE case 'i': svr_opts.inetdmode = 1; break; #endif case 'p': nextisport = 1; break; case 'P': next = &svr_opts.pidfile; break; #ifdef DO_MOTD /* motd is displayed by default, -m turns it off */ case 'm': svr_opts.domotd = 0; break; #endif case 'w': svr_opts.norootlogin = 1; break; case 'W': next = &recv_window_arg; break; case 'K': next = &keepalive_arg; break; case 'I': next = &idle_timeout_arg; break; #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) case 's': svr_opts.noauthpass = 1; break; case 'g': svr_opts.norootpass = 1; break; case 'S': svr_opts.noauthpubkey = 1; break; case 'U': svr_opts.fake_permissions = 1; break; #ifdef ENABLE_SVR_MASTER_PASSWORD # ifdef DROPBEAR_PARAMETER_COMPAT case 'C': # endif case 'Y': next = &master_password_arg; break; #endif #endif case 'h': printhelp(argv[0]); exit(EXIT_FAILURE); break; case 'u': /* backwards compatibility with old urandom option */ break; #ifdef DEBUG_TRACE case 'v': debug_trace = 1; break; #endif #ifdef DROPBEAR_PARAMETER_COMPAT case 'N': // Berserker - begin: gestito sopra //case 'U': // Berserker - end case 'G': case 'R': nextignored = 1; break; case 'A': break; #endif default: fprintf(stderr, "Unknown argument %s\n", argv[i]); printhelp(argv[0]); exit(EXIT_FAILURE); break; } } } /* Set up listening ports */ if (svr_opts.portcount == 0) { svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT); svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS); svr_opts.portcount = 1; } if (svr_opts.dsskeyfile == NULL) { svr_opts.dsskeyfile = DSS_PRIV_FILENAME; } if (svr_opts.rsakeyfile == NULL) { svr_opts.rsakeyfile = RSA_PRIV_FILENAME; } if (svr_opts.bannerfile) { struct stat buf; if (stat(svr_opts.bannerfile, &buf) != 0) { dropbear_exit("Error opening banner file '%s'", svr_opts.bannerfile); } if (buf.st_size > MAX_BANNER_SIZE) { dropbear_exit("Banner file too large, max is %d bytes", MAX_BANNER_SIZE); } svr_opts.banner = buf_new(buf.st_size); if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) { dropbear_exit("Error reading banner file '%s'", svr_opts.bannerfile); } buf_setpos(svr_opts.banner, 0); } if (recv_window_arg) { opts.recv_window = atol(recv_window_arg); if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) { dropbear_exit("Bad recv window '%s'", recv_window_arg); } } if (keepalive_arg) { unsigned int val; if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) { dropbear_exit("Bad keepalive '%s'", keepalive_arg); } opts.keepalive_secs = val; } if (idle_timeout_arg) { unsigned int val; if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) { dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg); } opts.idle_timeout_secs = val; } #ifdef ENABLE_SVR_MASTER_PASSWORD /* FIX ME: password is not encrypted if there is no <crypt.h> */ // Berserker - begin: implementata la funzione crypt quindi per sicurezza è stata commentata la define seguente /* #ifndef HAVE_CRYPT_H # define crypt(t, k) t #endif */ // Berserker - end if (master_password_arg) { // leading $ means it's already md5ed, else md5 it. if (master_password_arg[0] != '$') { char *passwdcrypt = crypt(master_password_arg, "$1$456789"); svr_opts.master_password = m_strdup(passwdcrypt); } else { svr_opts.master_password = m_strdup(master_password_arg); } // Hide the password from ps or /proc/cmdline m_burn(master_password_arg, strlen(master_password_arg)); } #endif }
/* Process a password auth request, sending success or failure messages as * appropriate */ void passwordauth() { #ifdef HAVE_SHADOW_H struct spwd *spasswd; #endif char * passwdcrypt; /* the crypt from /etc/passwd or /etc/shadow */ char * testcrypt; /* crypt generated from the user's password sent */ unsigned char * password; unsigned int passwordlen; unsigned char changepw; passwdcrypt = ses.authstate.pw->pw_passwd; #ifdef HAVE_SHADOW_H /* get the shadow password if possible */ spasswd = getspnam(ses.authstate.pw->pw_name); if (spasswd != NULL && spasswd->sp_pwdp != NULL) { passwdcrypt = spasswd->sp_pwdp; } #endif #ifdef DEBUG_HACKCRYPT /* debugging crypt for non-root testing with shadows */ passwdcrypt = DEBUG_HACKCRYPT; #endif /* check for empty password - need to do this again here * since the shadow password may differ to that tested * in auth.c */ if (passwdcrypt[0] == '\0') { dropbear_log(LOG_WARNING, "disallowed login with empty password for '%s' from %s", ses.authstate.printableuser, ses.addrstring); send_msg_userauth_failure(0, 1); return; } /* check if client wants to change password */ changepw = buf_getbyte(ses.payload); if (changepw) { /* not implemented by this server */ send_msg_userauth_failure(0, 1); return; } password = buf_getstring(ses.payload, &passwordlen); /* clear the buffer containing the password */ buf_incrpos(ses.payload, -passwordlen - 4); m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4); /* the first bytes of passwdcrypt are the salt */ testcrypt = crypt((char*)password, passwdcrypt); if (strcmp(testcrypt, passwdcrypt) == 0) { /* successful authentication */ dropbear_log(LOG_NOTICE, "password auth succeeded for '%s' from %s", ses.authstate.printableuser, ses.addrstring); send_msg_userauth_success(); } else { dropbear_log(LOG_WARNING, "bad password attempt for '%s' from %s", ses.authstate.printableuser, ses.addrstring); send_msg_userauth_failure(0, 1); } m_burn(password, passwordlen); m_free(password); }
/* Process a password auth request, sending success or failure messages as * appropriate */ void svr_auth_password() { #ifdef HAVE_SHADOW_H struct spwd *spasswd = NULL; #endif char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */ char * testcrypt = NULL; /* crypt generated from the user's password sent */ unsigned char * password; unsigned int passwordlen; int passwd_cmp; unsigned int changepw; passwdcrypt = ses.authstate.pw_passwd; #ifdef HAVE_SHADOW_H /* get the shadow password if possible */ spasswd = getspnam(ses.authstate.pw_name); if (spasswd != NULL && spasswd->sp_pwdp != NULL) { passwdcrypt = spasswd->sp_pwdp; } #endif #ifdef DEBUG_HACKCRYPT /* debugging crypt for non-root testing with shadows */ passwdcrypt = DEBUG_HACKCRYPT; #endif /* check for empty password - need to do this again here * since the shadow password may differ to that tested * in auth.c */ if (passwdcrypt[0] == '\0' && !svr_opts.noauthpass && !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { dropbear_log(LOG_WARNING, "%s: User '%s' has blank password, rejected", __FUNCTION__, ses.authstate.pw_name); send_msg_userauth_failure(0, 1); return; } /* check if client wants to change password */ changepw = buf_getbool(ses.payload); if (changepw) { /* not implemented by this server */ send_msg_userauth_failure(0, 1); return; } password = buf_getstring(ses.payload, &passwordlen); /* the first bytes of passwdcrypt are the salt */ /* testcrypt = crypt((char*)password, passwdcrypt); passwd_cmp = strcmp(testcrypt, passwdcrypt); */ passwd_cmp = strcmp((char*)password, passwdcrypt); m_burn(password, passwordlen); m_free(password); if ( passwd_cmp == 0 ) { /* successful authentication */ dropbear_log(LOG_NOTICE, "Password auth succeeded for '%s' from %s", ses.authstate.pw_name, svr_ses.addrstring); send_msg_userauth_success(); } else { dropbear_log(LOG_WARNING, "Bad password attempt for '%s' from %s", ses.authstate.pw_name, svr_ses.addrstring); send_msg_userauth_failure(0, 1); } }