diff --git a/cmdgen.c b/cmdgen.c index 774a42c7..e7e5a202 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -769,7 +769,7 @@ int main(int argc, char **argv) * Find out whether the input key is encrypted. */ if (intype == SSH_KEYTYPE_SSH1) - encrypted = rsakey_encrypted(infilename, &origcomment); + encrypted = rsa_ssh1_encrypted(infilename, &origcomment); else if (intype == SSH_KEYTYPE_SSH2) encrypted = ssh2_userkey_encrypted(infilename, &origcomment); else @@ -811,8 +811,8 @@ int main(int argc, char **argv) unsigned char *blob; int n, l, bloblen; - ret = rsakey_pubblob(infilename, &vblob, &bloblen, - &origcomment, &error); + ret = rsa_ssh1_loadpub(infilename, &vblob, &bloblen, + &origcomment, &error); blob = (unsigned char *)vblob; n = 4; /* skip modulus bits */ @@ -836,7 +836,8 @@ int main(int argc, char **argv) ssh1key->q = NULL; ssh1key->iqmp = NULL; } else { - ret = loadrsakey(infilename, ssh1key, old_passphrase, &error); + ret = rsa_ssh1_loadkey( + infilename, ssh1key, old_passphrase, &error); } if (ret > 0) error = NULL; @@ -972,7 +973,7 @@ int main(int argc, char **argv) case PRIVATE: if (sshver == 1) { assert(ssh1key); - ret = saversakey(outfilename, ssh1key, new_passphrase); + ret = rsa_ssh1_savekey(outfilename, ssh1key, new_passphrase); if (!ret) { fprintf(stderr, "puttygen: unable to save SSH-1 private key\n"); return 1; diff --git a/pageant.c b/pageant.c index a168e522..2f750398 100644 --- a/pageant.c +++ b/pageant.c @@ -11,8 +11,8 @@ #include "pageant.h" /* - * We need this to link with the RSA code, because rsaencrypt() - * pads its data with random bytes. Since we only use rsadecrypt() + * We need this to link with the RSA code, because rsa_ssh1_encrypt() + * pads its data with random bytes. Since we only use rsa_ssh1_decrypt() * and the signing functions, which are deterministic, this should * never be called. * @@ -182,7 +182,7 @@ void *pageant_make_keylist1(int *length) nkeys = 0; for (i = 0; NULL != (key = index234(rsakeys, i)); i++) { nkeys++; - blob = rsa_public_blob(key, &bloblen); + blob = rsa_ssh1_public_blob(key, &bloblen, RSA_SSH1_EXPONENT_FIRST); len += bloblen; sfree(blob); len += 4 + strlen(key->comment); @@ -195,7 +195,7 @@ void *pageant_make_keylist1(int *length) PUT_32BIT(p, nkeys); p += 4; for (i = 0; NULL != (key = index234(rsakeys, i)); i++) { - blob = rsa_public_blob(key, &bloblen); + blob = rsa_ssh1_public_blob(key, &bloblen, RSA_SSH1_EXPONENT_FIRST); memcpy(p, blob, bloblen); p += bloblen; sfree(blob); @@ -447,7 +447,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen, fail_reason = "key not found"; goto failure; } - response = rsadecrypt(challenge, key); + response = rsa_ssh1_decrypt(challenge, key); for (i = 0; i < 32; i++) response_source[i] = bignum_byte(response, 31 - i); @@ -547,7 +547,8 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen, key = snew(struct RSAKey); memset(key, 0, sizeof(struct RSAKey)); - n = makekey(p, msgend - p, key, NULL, 1); + n = rsa_ssh1_readpub(p, msgend - p, key, NULL, + RSA_SSH1_MODULUS_FIRST); if (n < 0) { freersakey(key); sfree(key); @@ -556,7 +557,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen, } p += n; - n = makeprivate(p, msgend - p, key); + n = rsa_ssh1_readpriv(p, msgend - p, key); if (n < 0) { freersakey(key); sfree(key); @@ -745,7 +746,8 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen, plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY"); - n = makekey(p, msgend - p, &reqkey, NULL, 0); + n = rsa_ssh1_readpub(p, msgend - p, &reqkey, NULL, + RSA_SSH1_EXPONENT_FIRST); if (n < 0) { fail_reason = "request truncated before public key"; goto failure; @@ -1286,7 +1288,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, int i, nkeys, bloblen, keylistlen; if (type == SSH_KEYTYPE_SSH1) { - if (!rsakey_pubblob(filename, &blob, &bloblen, NULL, &error)) { + if (!rsa_ssh1_loadpub(filename, &blob, &bloblen, NULL, &error)) { *retstr = dupprintf("Couldn't load private key (%s)", error); return PAGEANT_ACTION_FAILURE; } @@ -1396,7 +1398,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, error = NULL; if (type == SSH_KEYTYPE_SSH1) - needs_pass = rsakey_encrypted(filename, &comment); + needs_pass = rsa_ssh1_encrypted(filename, &comment); else needs_pass = ssh2_userkey_encrypted(filename, &comment); attempts = 0; @@ -1434,7 +1436,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, this_passphrase = ""; if (type == SSH_KEYTYPE_SSH1) - ret = loadrsakey(filename, rkey, this_passphrase, &error); + ret = rsa_ssh1_loadkey(filename, rkey, this_passphrase, &error); else { skey = ssh2_load_userkey(filename, this_passphrase, &error); if (skey == SSH2_WRONG_PASSPHRASE) @@ -1629,7 +1631,8 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, /* public blob and fingerprint */ memset(&rkey, 0, sizeof(rkey)); - n = makekey(p, keylistlen, &rkey, NULL, 0); + n = rsa_ssh1_readpub(p, keylistlen, &rkey, NULL, + RSA_SSH1_EXPONENT_FIRST); if (n < 0 || n > keylistlen) { freersakey(&rkey); *retstr = dupstr("Received broken SSH-1 key list from agent"); @@ -1657,7 +1660,8 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, comment = dupprintf("%.*s", (int)n, (const char *)p); p += n, keylistlen -= n; - cbkey.blob = rsa_public_blob(&rkey, &cbkey.bloblen); + cbkey.blob = rsa_ssh1_public_blob(&rkey, &cbkey.bloblen, + RSA_SSH1_EXPONENT_FIRST); cbkey.comment = comment; cbkey.ssh_version = 1; callback(callback_ctx, fingerprint, comment, &cbkey); diff --git a/ssh.c b/ssh.c index 5b9d0036..552b1cce 100644 --- a/ssh.c +++ b/ssh.c @@ -2871,9 +2871,9 @@ static int ssh1_pkt_getrsakey(struct Packet *pkt, struct RSAKey *key, { int j; - j = makekey(pkt->body + pkt->savedpos, - pkt->length - pkt->savedpos, - key, keystr, 0); + j = rsa_ssh1_readpub(pkt->body + pkt->savedpos, + pkt->length - pkt->savedpos, + key, keystr, RSA_SSH1_EXPONENT_FIRST); if (j < 0) return FALSE; @@ -4424,13 +4424,13 @@ static void do_ssh1_login(void *vctx) } if (s->hostkey.bytes > s->servkey.bytes) { - ret = rsaencrypt(s->rsabuf, 32, &s->servkey); + ret = rsa_ssh1_encrypt(s->rsabuf, 32, &s->servkey); if (ret) - ret = rsaencrypt(s->rsabuf, s->servkey.bytes, &s->hostkey); + ret = rsa_ssh1_encrypt(s->rsabuf, s->servkey.bytes, &s->hostkey); } else { - ret = rsaencrypt(s->rsabuf, 32, &s->hostkey); + ret = rsa_ssh1_encrypt(s->rsabuf, 32, &s->hostkey); if (ret) - ret = rsaencrypt(s->rsabuf, s->hostkey.bytes, &s->servkey); + ret = rsa_ssh1_encrypt(s->rsabuf, s->hostkey.bytes, &s->servkey); } if (!ret) { bombout(("SSH-1 public key encryptions failed due to bad formatting")); @@ -4617,14 +4617,13 @@ static void do_ssh1_login(void *vctx) if (keytype == SSH_KEYTYPE_SSH1 || keytype == SSH_KEYTYPE_SSH1_PUBLIC) { const char *error; - if (rsakey_pubblob(s->keyfile, - &s->publickey_blob, &s->publickey_bloblen, - &s->publickey_comment, &error)) { + if (rsa_ssh1_loadpub(s->keyfile, + &s->publickey_blob, &s->publickey_bloblen, + &s->publickey_comment, &error)) { s->privatekey_available = (keytype == SSH_KEYTYPE_SSH1); if (!s->privatekey_available) logeventf(ssh, "Key file contains public key only"); - s->privatekey_encrypted = rsakey_encrypted(s->keyfile, - NULL); + s->privatekey_encrypted = rsa_ssh1_encrypted(s->keyfile, NULL); } else { char *msgbuf; logeventf(ssh, "Unable to load key (%s)", error); @@ -4888,8 +4887,8 @@ static void do_ssh1_login(void *vctx) * Try decrypting key with passphrase. */ s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); - ret = loadrsakey(s->keyfile, &s->key, passphrase, - &error); + ret = rsa_ssh1_loadkey( + s->keyfile, &s->key, passphrase, &error); if (passphrase) { smemclr(passphrase, strlen(passphrase)); sfree(passphrase); @@ -4910,7 +4909,7 @@ static void do_ssh1_login(void *vctx) got_passphrase = FALSE; /* and try again */ } else { - assert(0 && "unexpected return from loadrsakey()"); + assert(0 && "unexpected return from rsa_ssh1_loadkey()"); got_passphrase = FALSE; /* placate optimisers */ } } @@ -4943,7 +4942,7 @@ static void do_ssh1_login(void *vctx) bombout(("Server's RSA challenge was badly formatted")); crStopV; } - response = rsadecrypt(challenge, &s->key); + response = rsa_ssh1_decrypt(challenge, &s->key); freebn(s->key.private_exponent);/* burn the evidence */ for (i = 0; i < 32; i++) { diff --git a/ssh.h b/ssh.h index a7902f2c..579fd2cd 100644 --- a/ssh.h +++ b/ssh.h @@ -173,18 +173,29 @@ struct ec_key { struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve); -int makekey(const unsigned char *data, int len, struct RSAKey *result, - const unsigned char **keystr, int order); -int makeprivate(const unsigned char *data, int len, struct RSAKey *result); -int rsaencrypt(unsigned char *data, int length, struct RSAKey *key); -Bignum rsadecrypt(Bignum input, struct RSAKey *key); -void rsasign(unsigned char *data, int length, struct RSAKey *key); +/* + * SSH-1 never quite decided which order to store the two components + * of an RSA key. During connection setup, the server sends its host + * and server keys with the exponent first; private key files store + * the modulus first. The agent protocol is even more confusing, + * because the client specifies a key to the server in one order and + * the server lists the keys it knows about in the other order! + */ +typedef enum { RSA_SSH1_EXPONENT_FIRST, RSA_SSH1_MODULUS_FIRST } RsaSsh1Order; + +int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result, + const unsigned char **keystr, RsaSsh1Order order); +int rsa_ssh1_readpriv(const unsigned char *data, int len, + struct RSAKey *result); +int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key); +Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key); void rsasanitise(struct RSAKey *key); int rsastr_len(struct RSAKey *key); void rsastr_fmt(char *str, struct RSAKey *key); void rsa_fingerprint(char *str, int len, struct RSAKey *key); int rsa_verify(struct RSAKey *key); -unsigned char *rsa_public_blob(struct RSAKey *key, int *len); +unsigned char *rsa_ssh1_public_blob(struct RSAKey *key, int *len, + RsaSsh1Order order); int rsa_public_blob_len(void *data, int maxlen); void freersakey(struct RSAKey *key); @@ -711,13 +722,13 @@ Bignum dh_create_e(void *, int nbits); const char *dh_validate_f(void *handle, Bignum f); Bignum dh_find_K(void *, Bignum f); -int loadrsakey(const Filename *filename, struct RSAKey *key, - const char *passphrase, const char **errorstr); -int rsakey_encrypted(const Filename *filename, char **comment); -int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen, - char **commentptr, const char **errorstr); - -int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase); +int rsa_ssh1_encrypted(const Filename *filename, char **comment); +int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen, + char **commentptr, const char **errorstr); +int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key, + const char *passphrase, const char **errorstr); +int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, + char *passphrase); extern int base64_decode_atom(const char *atom, unsigned char *out); extern int base64_lines(int datalen); diff --git a/sshpubk.c b/sshpubk.c index 1a27c313..c60b9dfc 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -23,9 +23,9 @@ static int key_type_fp(FILE *fp); -static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only, - char **commentptr, const char *passphrase, - const char **error) +static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, int pub_only, + char **commentptr, const char *passphrase, + const char **error) { unsigned char buf[16384]; unsigned char keybuf[16]; @@ -69,7 +69,7 @@ static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only, i += 4; /* Now the serious stuff. An ordinary SSH-1 public key. */ - j = makekey(buf + i, len - i, key, NULL, 1); + j = rsa_ssh1_readpub(buf + i, len - i, key, NULL, RSA_SSH1_MODULUS_FIRST); if (j < 0) goto end; /* overran */ i += j; @@ -132,7 +132,7 @@ static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only, * decryption exponent, and then the three auxiliary values * (iqmp, q, p). */ - j = makeprivate(buf + i, len - i, key); + j = rsa_ssh1_readpriv(buf + i, len - i, key); if (j < 0) goto end; i += j; j = ssh1_read_bignum(buf + i, len - i, &key->iqmp); @@ -157,8 +157,8 @@ static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only, return ret; } -int loadrsakey(const Filename *filename, struct RSAKey *key, - const char *passphrase, const char **errorstr) +int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key, + const char *passphrase, const char **errorstr) { FILE *fp; char buf[64]; @@ -179,7 +179,7 @@ int loadrsakey(const Filename *filename, struct RSAKey *key, /* * This routine will take care of calling fclose() for us. */ - ret = loadrsakey_main(fp, key, FALSE, NULL, passphrase, &error); + ret = rsa_ssh1_load_main(fp, key, FALSE, NULL, passphrase, &error); fp = NULL; goto end; } @@ -201,7 +201,7 @@ int loadrsakey(const Filename *filename, struct RSAKey *key, * See whether an RSA key is encrypted. Return its comment field as * well. */ -int rsakey_encrypted(const Filename *filename, char **comment) +int rsa_ssh1_encrypted(const Filename *filename, char **comment) { FILE *fp; char buf[64]; @@ -219,7 +219,7 @@ int rsakey_encrypted(const Filename *filename, char **comment) /* * This routine will take care of calling fclose() for us. */ - return loadrsakey_main(fp, NULL, FALSE, comment, NULL, &dummy); + return rsa_ssh1_load_main(fp, NULL, FALSE, comment, NULL, &dummy); } fclose(fp); return 0; /* wasn't the right kind of file */ @@ -230,8 +230,8 @@ int rsakey_encrypted(const Filename *filename, char **comment) * an RSA key, as given in the agent protocol (modulus bits, * exponent, modulus). */ -int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen, - char **commentptr, const char **errorstr) +int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen, + char **commentptr, const char **errorstr) { FILE *fp; char buf[64]; @@ -256,12 +256,13 @@ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen, */ if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) { memset(&key, 0, sizeof(key)); - if (loadrsakey_main(fp, &key, TRUE, commentptr, NULL, &error)) { - *blob = rsa_public_blob(&key, bloblen); + if (rsa_ssh1_load_main(fp, &key, TRUE, commentptr, NULL, &error)) { + *blob = rsa_ssh1_public_blob(&key, bloblen, + RSA_SSH1_EXPONENT_FIRST); freersakey(&key); ret = 1; } - fp = NULL; /* loadrsakey_main unconditionally closes fp */ + fp = NULL; /* rsa_ssh1_load_main unconditionally closes fp */ } else { /* * Try interpreting the file as an SSH-1 public key. @@ -307,7 +308,7 @@ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen, } if (commentptr) *commentptr = commentp ? dupstr(commentp) : NULL; - *blob = rsa_public_blob(&key, bloblen); + *blob = rsa_ssh1_public_blob(&key, bloblen, RSA_SSH1_EXPONENT_FIRST); freersakey(&key); sfree(line); fclose(fp); @@ -329,7 +330,8 @@ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen, /* * Save an RSA key file. Return nonzero on success. */ -int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase) +int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, + char *passphrase) { unsigned char buf[16384]; unsigned char keybuf[16]; diff --git a/sshrsa.c b/sshrsa.c index e565a64a..fada7390 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -10,8 +10,8 @@ #include "ssh.h" #include "misc.h" -int makekey(const unsigned char *data, int len, struct RSAKey *result, - const unsigned char **keystr, int order) +int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result, + const unsigned char **keystr, RsaSsh1Order order) { const unsigned char *p = data; int i, n; @@ -28,13 +28,7 @@ int makekey(const unsigned char *data, int len, struct RSAKey *result, len -= 4; - /* - * order=0 means exponent then modulus (the keys sent by the - * server). order=1 means modulus then exponent (the keys - * stored in a keyfile). - */ - - if (order == 0) { + if (order == RSA_SSH1_EXPONENT_FIRST) { n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL); if (n < 0) return -1; p += n; @@ -50,7 +44,7 @@ int makekey(const unsigned char *data, int len, struct RSAKey *result, p += n; len -= n; - if (order == 1) { + if (order == RSA_SSH1_MODULUS_FIRST) { n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL); if (n < 0) return -1; p += n; @@ -59,12 +53,13 @@ int makekey(const unsigned char *data, int len, struct RSAKey *result, return p - data; } -int makeprivate(const unsigned char *data, int len, struct RSAKey *result) +int rsa_ssh1_readpriv(const unsigned char *data, int len, + struct RSAKey *result) { return ssh1_read_bignum(data, len, &result->private_exponent); } -int rsaencrypt(unsigned char *data, int length, struct RSAKey *key) +int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key) { Bignum b1, b2; int i; @@ -318,7 +313,7 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key) return ret; } -Bignum rsadecrypt(Bignum input, struct RSAKey *key) +Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key) { return rsa_privkey_op(input, key); } @@ -468,8 +463,8 @@ int rsa_verify(struct RSAKey *key) return 1; } -/* Public key blob as used by Pageant: exponent before modulus. */ -unsigned char *rsa_public_blob(struct RSAKey *key, int *len) +unsigned char *rsa_ssh1_public_blob(struct RSAKey *key, int *len, + RsaSsh1Order order) { int length, pos; unsigned char *ret; @@ -480,8 +475,13 @@ unsigned char *rsa_public_blob(struct RSAKey *key, int *len) PUT_32BIT(ret, bignum_bitcount(key->modulus)); pos = 4; - pos += ssh1_write_bignum(ret + pos, key->exponent); - pos += ssh1_write_bignum(ret + pos, key->modulus); + if (order == RSA_SSH1_EXPONENT_FIRST) { + pos += ssh1_write_bignum(ret + pos, key->exponent); + pos += ssh1_write_bignum(ret + pos, key->modulus); + } else { + pos += ssh1_write_bignum(ret + pos, key->modulus); + pos += ssh1_write_bignum(ret + pos, key->exponent); + } *len = length; return ret; diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index d3f5648e..f7408325 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -556,8 +556,8 @@ struct pageant_pubkey *find_key(const char *string, char **retstr) keytype == SSH_KEYTYPE_SSH1_PUBLIC) { const char *error; - if (!rsakey_pubblob(fn, &key_in.blob, &key_in.bloblen, - NULL, &error)) { + if (!rsa_ssh1_loadpub(fn, &key_in.blob, &key_in.bloblen, + NULL, &error)) { if (file_errors) { *retstr = dupprintf("unable to load file '%s': %s", string, error); @@ -696,7 +696,8 @@ void run_client(void) struct RSAKey rkey; memset(&rkey, 0, sizeof(rkey)); rkey.comment = dupstr(key->comment); - makekey(key->blob, key->bloblen, &rkey, NULL, 0); + rsa_ssh1_readpub(key->blob, key->bloblen, &rkey, NULL, + RSA_SSH1_EXPONENT_FIRST); ssh1_write_pubkey(fp, &rkey); freersakey(&rkey); } else { diff --git a/windows/winpgen.c b/windows/winpgen.c index 7903c1cf..e253f9cb 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -671,7 +671,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, comment = NULL; passphrase = NULL; if (realtype == SSH_KEYTYPE_SSH1) - needs_pass = rsakey_encrypted(filename, &comment); + needs_pass = rsa_ssh1_encrypted(filename, &comment); else if (realtype == SSH_KEYTYPE_SSH2) needs_pass = ssh2_userkey_encrypted(filename, &comment); else @@ -698,7 +698,8 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, passphrase = dupstr(""); if (type == SSH_KEYTYPE_SSH1) { if (realtype == type) - ret = loadrsakey(filename, &newkey1, passphrase, &errmsg); + ret = rsa_ssh1_loadkey( + filename, &newkey1, passphrase, &errmsg); else ret = import_ssh1(filename, realtype, &newkey1, passphrase, &errmsg); @@ -1279,8 +1280,9 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, ret = export_ssh1(fn, type, &state->key, *passphrase ? passphrase : NULL); else - ret = saversakey(fn, &state->key, - *passphrase ? passphrase : NULL); + ret = rsa_ssh1_savekey( + fn, &state->key, + *passphrase ? passphrase : NULL); filename_free(fn); } if (ret <= 0) {