diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 311 |
1 files changed, 10 insertions, 301 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 21a269d3c..66cb03527 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.201 2014/01/09 23:20:00 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.204 2014/02/02 03:44:32 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -70,8 +70,6 @@ | |||
70 | #include "pathnames.h" | 70 | #include "pathnames.h" |
71 | #include "uidswap.h" | 71 | #include "uidswap.h" |
72 | #include "hostfile.h" | 72 | #include "hostfile.h" |
73 | #include "schnorr.h" | ||
74 | #include "jpake.h" | ||
75 | 73 | ||
76 | #ifdef GSSAPI | 74 | #ifdef GSSAPI |
77 | #include "ssh-gss.h" | 75 | #include "ssh-gss.h" |
@@ -345,18 +343,12 @@ void input_userauth_error(int, u_int32_t, void *); | |||
345 | void input_userauth_info_req(int, u_int32_t, void *); | 343 | void input_userauth_info_req(int, u_int32_t, void *); |
346 | void input_userauth_pk_ok(int, u_int32_t, void *); | 344 | void input_userauth_pk_ok(int, u_int32_t, void *); |
347 | void input_userauth_passwd_changereq(int, u_int32_t, void *); | 345 | void input_userauth_passwd_changereq(int, u_int32_t, void *); |
348 | void input_userauth_jpake_server_step1(int, u_int32_t, void *); | ||
349 | void input_userauth_jpake_server_step2(int, u_int32_t, void *); | ||
350 | void input_userauth_jpake_server_confirm(int, u_int32_t, void *); | ||
351 | 346 | ||
352 | int userauth_none(Authctxt *); | 347 | int userauth_none(Authctxt *); |
353 | int userauth_pubkey(Authctxt *); | 348 | int userauth_pubkey(Authctxt *); |
354 | int userauth_passwd(Authctxt *); | 349 | int userauth_passwd(Authctxt *); |
355 | int userauth_kbdint(Authctxt *); | 350 | int userauth_kbdint(Authctxt *); |
356 | int userauth_hostbased(Authctxt *); | 351 | int userauth_hostbased(Authctxt *); |
357 | int userauth_jpake(Authctxt *); | ||
358 | |||
359 | void userauth_jpake_cleanup(Authctxt *); | ||
360 | 352 | ||
361 | #ifdef GSSAPI | 353 | #ifdef GSSAPI |
362 | int userauth_gssapi(Authctxt *authctxt); | 354 | int userauth_gssapi(Authctxt *authctxt); |
@@ -402,13 +394,6 @@ Authmethod authmethods[] = { | |||
402 | NULL, | 394 | NULL, |
403 | &options.pubkey_authentication, | 395 | &options.pubkey_authentication, |
404 | NULL}, | 396 | NULL}, |
405 | #ifdef JPAKE | ||
406 | {"jpake-01@openssh.com", | ||
407 | userauth_jpake, | ||
408 | userauth_jpake_cleanup, | ||
409 | &options.zero_knowledge_password_authentication, | ||
410 | &options.batch_mode}, | ||
411 | #endif | ||
412 | {"keyboard-interactive", | 397 | {"keyboard-interactive", |
413 | userauth_kbdint, | 398 | userauth_kbdint, |
414 | NULL, | 399 | NULL, |
@@ -1000,7 +985,7 @@ userauth_passwd(Authctxt *authctxt) | |||
1000 | packet_put_cstring(authctxt->method->name); | 985 | packet_put_cstring(authctxt->method->name); |
1001 | packet_put_char(0); | 986 | packet_put_char(0); |
1002 | packet_put_cstring(password); | 987 | packet_put_cstring(password); |
1003 | memset(password, 0, strlen(password)); | 988 | explicit_bzero(password, strlen(password)); |
1004 | free(password); | 989 | free(password); |
1005 | packet_add_padding(64); | 990 | packet_add_padding(64); |
1006 | packet_send(); | 991 | packet_send(); |
@@ -1046,7 +1031,7 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
1046 | authctxt->server_user, host); | 1031 | authctxt->server_user, host); |
1047 | password = read_passphrase(prompt, 0); | 1032 | password = read_passphrase(prompt, 0); |
1048 | packet_put_cstring(password); | 1033 | packet_put_cstring(password); |
1049 | memset(password, 0, strlen(password)); | 1034 | explicit_bzero(password, strlen(password)); |
1050 | free(password); | 1035 | free(password); |
1051 | password = NULL; | 1036 | password = NULL; |
1052 | while (password == NULL) { | 1037 | while (password == NULL) { |
@@ -1063,16 +1048,16 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
1063 | authctxt->server_user, host); | 1048 | authctxt->server_user, host); |
1064 | retype = read_passphrase(prompt, 0); | 1049 | retype = read_passphrase(prompt, 0); |
1065 | if (strcmp(password, retype) != 0) { | 1050 | if (strcmp(password, retype) != 0) { |
1066 | memset(password, 0, strlen(password)); | 1051 | explicit_bzero(password, strlen(password)); |
1067 | free(password); | 1052 | free(password); |
1068 | logit("Mismatch; try again, EOF to quit."); | 1053 | logit("Mismatch; try again, EOF to quit."); |
1069 | password = NULL; | 1054 | password = NULL; |
1070 | } | 1055 | } |
1071 | memset(retype, 0, strlen(retype)); | 1056 | explicit_bzero(retype, strlen(retype)); |
1072 | free(retype); | 1057 | free(retype); |
1073 | } | 1058 | } |
1074 | packet_put_cstring(password); | 1059 | packet_put_cstring(password); |
1075 | memset(password, 0, strlen(password)); | 1060 | explicit_bzero(password, strlen(password)); |
1076 | free(password); | 1061 | free(password); |
1077 | packet_add_padding(64); | 1062 | packet_add_padding(64); |
1078 | packet_send(); | 1063 | packet_send(); |
@@ -1081,209 +1066,6 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
1081 | &input_userauth_passwd_changereq); | 1066 | &input_userauth_passwd_changereq); |
1082 | } | 1067 | } |
1083 | 1068 | ||
1084 | #ifdef JPAKE | ||
1085 | static char * | ||
1086 | pw_encrypt(const char *password, const char *crypt_scheme, const char *salt) | ||
1087 | { | ||
1088 | /* OpenBSD crypt(3) handles all of these */ | ||
1089 | if (strcmp(crypt_scheme, "crypt") == 0 || | ||
1090 | strcmp(crypt_scheme, "bcrypt") == 0 || | ||
1091 | strcmp(crypt_scheme, "md5crypt") == 0 || | ||
1092 | strcmp(crypt_scheme, "crypt-extended") == 0) | ||
1093 | return xstrdup(crypt(password, salt)); | ||
1094 | error("%s: unsupported password encryption scheme \"%.100s\"", | ||
1095 | __func__, crypt_scheme); | ||
1096 | return NULL; | ||
1097 | } | ||
1098 | |||
1099 | static BIGNUM * | ||
1100 | jpake_password_to_secret(Authctxt *authctxt, const char *crypt_scheme, | ||
1101 | const char *salt) | ||
1102 | { | ||
1103 | char prompt[256], *password, *crypted; | ||
1104 | u_char *secret; | ||
1105 | u_int secret_len; | ||
1106 | BIGNUM *ret; | ||
1107 | |||
1108 | snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password (JPAKE): ", | ||
1109 | authctxt->server_user, authctxt->host); | ||
1110 | password = read_passphrase(prompt, 0); | ||
1111 | |||
1112 | if ((crypted = pw_encrypt(password, crypt_scheme, salt)) == NULL) { | ||
1113 | logit("Disabling %s authentication", authctxt->method->name); | ||
1114 | authctxt->method->enabled = NULL; | ||
1115 | /* Continue with an empty password to fail gracefully */ | ||
1116 | crypted = xstrdup(""); | ||
1117 | } | ||
1118 | |||
1119 | #ifdef JPAKE_DEBUG | ||
1120 | debug3("%s: salt = %s", __func__, salt); | ||
1121 | debug3("%s: scheme = %s", __func__, crypt_scheme); | ||
1122 | debug3("%s: crypted = %s", __func__, crypted); | ||
1123 | #endif | ||
1124 | |||
1125 | if (hash_buffer(crypted, strlen(crypted), SSH_DIGEST_SHA1, | ||
1126 | &secret, &secret_len) != 0) | ||
1127 | fatal("%s: hash_buffer", __func__); | ||
1128 | |||
1129 | bzero(password, strlen(password)); | ||
1130 | bzero(crypted, strlen(crypted)); | ||
1131 | free(password); | ||
1132 | free(crypted); | ||
1133 | |||
1134 | if ((ret = BN_bin2bn(secret, secret_len, NULL)) == NULL) | ||
1135 | fatal("%s: BN_bin2bn (secret)", __func__); | ||
1136 | bzero(secret, secret_len); | ||
1137 | free(secret); | ||
1138 | |||
1139 | return ret; | ||
1140 | } | ||
1141 | |||
1142 | /* ARGSUSED */ | ||
1143 | void | ||
1144 | input_userauth_jpake_server_step1(int type, u_int32_t seq, void *ctxt) | ||
1145 | { | ||
1146 | Authctxt *authctxt = ctxt; | ||
1147 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1148 | u_char *x3_proof, *x4_proof, *x2_s_proof; | ||
1149 | u_int x3_proof_len, x4_proof_len, x2_s_proof_len; | ||
1150 | char *crypt_scheme, *salt; | ||
1151 | |||
1152 | /* Disable this message */ | ||
1153 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, NULL); | ||
1154 | |||
1155 | if ((pctx->g_x3 = BN_new()) == NULL || | ||
1156 | (pctx->g_x4 = BN_new()) == NULL) | ||
1157 | fatal("%s: BN_new", __func__); | ||
1158 | |||
1159 | /* Fetch step 1 values */ | ||
1160 | crypt_scheme = packet_get_string(NULL); | ||
1161 | salt = packet_get_string(NULL); | ||
1162 | pctx->server_id = packet_get_string(&pctx->server_id_len); | ||
1163 | packet_get_bignum2(pctx->g_x3); | ||
1164 | packet_get_bignum2(pctx->g_x4); | ||
1165 | x3_proof = packet_get_string(&x3_proof_len); | ||
1166 | x4_proof = packet_get_string(&x4_proof_len); | ||
1167 | packet_check_eom(); | ||
1168 | |||
1169 | JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__)); | ||
1170 | |||
1171 | /* Obtain password and derive secret */ | ||
1172 | pctx->s = jpake_password_to_secret(authctxt, crypt_scheme, salt); | ||
1173 | bzero(crypt_scheme, strlen(crypt_scheme)); | ||
1174 | bzero(salt, strlen(salt)); | ||
1175 | free(crypt_scheme); | ||
1176 | free(salt); | ||
1177 | JPAKE_DEBUG_BN((pctx->s, "%s: s = ", __func__)); | ||
1178 | |||
1179 | /* Calculate step 2 values */ | ||
1180 | jpake_step2(pctx->grp, pctx->s, pctx->g_x1, | ||
1181 | pctx->g_x3, pctx->g_x4, pctx->x2, | ||
1182 | pctx->server_id, pctx->server_id_len, | ||
1183 | pctx->client_id, pctx->client_id_len, | ||
1184 | x3_proof, x3_proof_len, | ||
1185 | x4_proof, x4_proof_len, | ||
1186 | &pctx->a, | ||
1187 | &x2_s_proof, &x2_s_proof_len); | ||
1188 | |||
1189 | bzero(x3_proof, x3_proof_len); | ||
1190 | bzero(x4_proof, x4_proof_len); | ||
1191 | free(x3_proof); | ||
1192 | free(x4_proof); | ||
1193 | |||
1194 | JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__)); | ||
1195 | |||
1196 | /* Send values for step 2 */ | ||
1197 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2); | ||
1198 | packet_put_bignum2(pctx->a); | ||
1199 | packet_put_string(x2_s_proof, x2_s_proof_len); | ||
1200 | packet_send(); | ||
1201 | |||
1202 | bzero(x2_s_proof, x2_s_proof_len); | ||
1203 | free(x2_s_proof); | ||
1204 | |||
1205 | /* Expect step 2 packet from peer */ | ||
1206 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, | ||
1207 | input_userauth_jpake_server_step2); | ||
1208 | } | ||
1209 | |||
1210 | /* ARGSUSED */ | ||
1211 | void | ||
1212 | input_userauth_jpake_server_step2(int type, u_int32_t seq, void *ctxt) | ||
1213 | { | ||
1214 | Authctxt *authctxt = ctxt; | ||
1215 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1216 | u_char *x4_s_proof; | ||
1217 | u_int x4_s_proof_len; | ||
1218 | |||
1219 | /* Disable this message */ | ||
1220 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, NULL); | ||
1221 | |||
1222 | if ((pctx->b = BN_new()) == NULL) | ||
1223 | fatal("%s: BN_new", __func__); | ||
1224 | |||
1225 | /* Fetch step 2 values */ | ||
1226 | packet_get_bignum2(pctx->b); | ||
1227 | x4_s_proof = packet_get_string(&x4_s_proof_len); | ||
1228 | packet_check_eom(); | ||
1229 | |||
1230 | JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__)); | ||
1231 | |||
1232 | /* Derive shared key and calculate confirmation hash */ | ||
1233 | jpake_key_confirm(pctx->grp, pctx->s, pctx->b, | ||
1234 | pctx->x2, pctx->g_x1, pctx->g_x2, pctx->g_x3, pctx->g_x4, | ||
1235 | pctx->client_id, pctx->client_id_len, | ||
1236 | pctx->server_id, pctx->server_id_len, | ||
1237 | session_id2, session_id2_len, | ||
1238 | x4_s_proof, x4_s_proof_len, | ||
1239 | &pctx->k, | ||
1240 | &pctx->h_k_cid_sessid, &pctx->h_k_cid_sessid_len); | ||
1241 | |||
1242 | bzero(x4_s_proof, x4_s_proof_len); | ||
1243 | free(x4_s_proof); | ||
1244 | |||
1245 | JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__)); | ||
1246 | |||
1247 | /* Send key confirmation proof */ | ||
1248 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM); | ||
1249 | packet_put_string(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len); | ||
1250 | packet_send(); | ||
1251 | |||
1252 | /* Expect confirmation from peer */ | ||
1253 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, | ||
1254 | input_userauth_jpake_server_confirm); | ||
1255 | } | ||
1256 | |||
1257 | /* ARGSUSED */ | ||
1258 | void | ||
1259 | input_userauth_jpake_server_confirm(int type, u_int32_t seq, void *ctxt) | ||
1260 | { | ||
1261 | Authctxt *authctxt = ctxt; | ||
1262 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1263 | |||
1264 | /* Disable this message */ | ||
1265 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, NULL); | ||
1266 | |||
1267 | pctx->h_k_sid_sessid = packet_get_string(&pctx->h_k_sid_sessid_len); | ||
1268 | packet_check_eom(); | ||
1269 | |||
1270 | JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__)); | ||
1271 | |||
1272 | /* Verify expected confirmation hash */ | ||
1273 | if (jpake_check_confirm(pctx->k, | ||
1274 | pctx->server_id, pctx->server_id_len, | ||
1275 | session_id2, session_id2_len, | ||
1276 | pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len) == 1) | ||
1277 | debug("%s: %s success", __func__, authctxt->method->name); | ||
1278 | else { | ||
1279 | debug("%s: confirmation mismatch", __func__); | ||
1280 | /* XXX stash this so if auth succeeds then we can warn/kill */ | ||
1281 | } | ||
1282 | |||
1283 | userauth_jpake_cleanup(authctxt); | ||
1284 | } | ||
1285 | #endif /* JPAKE */ | ||
1286 | |||
1287 | static int | 1069 | static int |
1288 | identity_sign(Identity *id, u_char **sigp, u_int *lenp, | 1070 | identity_sign(Identity *id, u_char **sigp, u_int *lenp, |
1289 | u_char *data, u_int datalen) | 1071 | u_char *data, u_int datalen) |
@@ -1460,7 +1242,7 @@ load_identity_file(char *filename, int userprovided) | |||
1460 | debug2("no passphrase given, try next key"); | 1242 | debug2("no passphrase given, try next key"); |
1461 | quit = 1; | 1243 | quit = 1; |
1462 | } | 1244 | } |
1463 | memset(passphrase, 0, strlen(passphrase)); | 1245 | explicit_bzero(passphrase, strlen(passphrase)); |
1464 | free(passphrase); | 1246 | free(passphrase); |
1465 | if (private != NULL || quit) | 1247 | if (private != NULL || quit) |
1466 | break; | 1248 | break; |
@@ -1524,7 +1306,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1524 | /* If IdentitiesOnly set and key not found then don't use it */ | 1306 | /* If IdentitiesOnly set and key not found then don't use it */ |
1525 | if (!found && options.identities_only) { | 1307 | if (!found && options.identities_only) { |
1526 | TAILQ_REMOVE(&files, id, next); | 1308 | TAILQ_REMOVE(&files, id, next); |
1527 | bzero(id, sizeof(*id)); | 1309 | explicit_bzero(id, sizeof(*id)); |
1528 | free(id); | 1310 | free(id); |
1529 | } | 1311 | } |
1530 | } | 1312 | } |
@@ -1719,7 +1501,7 @@ input_userauth_info_req(int type, u_int32_t seq, void *ctxt) | |||
1719 | response = read_passphrase(prompt, echo ? RP_ECHO : 0); | 1501 | response = read_passphrase(prompt, echo ? RP_ECHO : 0); |
1720 | 1502 | ||
1721 | packet_put_cstring(response); | 1503 | packet_put_cstring(response); |
1722 | memset(response, 0, strlen(response)); | 1504 | explicit_bzero(response, strlen(response)); |
1723 | free(response); | 1505 | free(response); |
1724 | free(prompt); | 1506 | free(prompt); |
1725 | } | 1507 | } |
@@ -1889,7 +1671,7 @@ userauth_hostbased(Authctxt *authctxt) | |||
1889 | packet_put_cstring(chost); | 1671 | packet_put_cstring(chost); |
1890 | packet_put_cstring(authctxt->local_user); | 1672 | packet_put_cstring(authctxt->local_user); |
1891 | packet_put_string(signature, slen); | 1673 | packet_put_string(signature, slen); |
1892 | memset(signature, 's', slen); | 1674 | explicit_bzero(signature, slen); |
1893 | free(signature); | 1675 | free(signature); |
1894 | free(chost); | 1676 | free(chost); |
1895 | free(pkalg); | 1677 | free(pkalg); |
@@ -1899,79 +1681,6 @@ userauth_hostbased(Authctxt *authctxt) | |||
1899 | return 1; | 1681 | return 1; |
1900 | } | 1682 | } |
1901 | 1683 | ||
1902 | #ifdef JPAKE | ||
1903 | int | ||
1904 | userauth_jpake(Authctxt *authctxt) | ||
1905 | { | ||
1906 | struct jpake_ctx *pctx; | ||
1907 | u_char *x1_proof, *x2_proof; | ||
1908 | u_int x1_proof_len, x2_proof_len; | ||
1909 | static int attempt = 0; /* XXX share with userauth_password's? */ | ||
1910 | |||
1911 | if (attempt++ >= options.number_of_password_prompts) | ||
1912 | return 0; | ||
1913 | if (attempt != 1) | ||
1914 | error("Permission denied, please try again."); | ||
1915 | |||
1916 | if (authctxt->methoddata != NULL) | ||
1917 | fatal("%s: authctxt->methoddata already set (%p)", | ||
1918 | __func__, authctxt->methoddata); | ||
1919 | |||
1920 | authctxt->methoddata = pctx = jpake_new(); | ||
1921 | |||
1922 | /* | ||
1923 | * Send request immediately, to get the protocol going while | ||
1924 | * we do the initial computations. | ||
1925 | */ | ||
1926 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
1927 | packet_put_cstring(authctxt->server_user); | ||
1928 | packet_put_cstring(authctxt->service); | ||
1929 | packet_put_cstring(authctxt->method->name); | ||
1930 | packet_send(); | ||
1931 | packet_write_wait(); | ||
1932 | |||
1933 | jpake_step1(pctx->grp, | ||
1934 | &pctx->client_id, &pctx->client_id_len, | ||
1935 | &pctx->x1, &pctx->x2, &pctx->g_x1, &pctx->g_x2, | ||
1936 | &x1_proof, &x1_proof_len, | ||
1937 | &x2_proof, &x2_proof_len); | ||
1938 | |||
1939 | JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__)); | ||
1940 | |||
1941 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1); | ||
1942 | packet_put_string(pctx->client_id, pctx->client_id_len); | ||
1943 | packet_put_bignum2(pctx->g_x1); | ||
1944 | packet_put_bignum2(pctx->g_x2); | ||
1945 | packet_put_string(x1_proof, x1_proof_len); | ||
1946 | packet_put_string(x2_proof, x2_proof_len); | ||
1947 | packet_send(); | ||
1948 | |||
1949 | bzero(x1_proof, x1_proof_len); | ||
1950 | bzero(x2_proof, x2_proof_len); | ||
1951 | free(x1_proof); | ||
1952 | free(x2_proof); | ||
1953 | |||
1954 | /* Expect step 1 packet from peer */ | ||
1955 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, | ||
1956 | input_userauth_jpake_server_step1); | ||
1957 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, | ||
1958 | &input_userauth_success_unexpected); | ||
1959 | |||
1960 | return 1; | ||
1961 | } | ||
1962 | |||
1963 | void | ||
1964 | userauth_jpake_cleanup(Authctxt *authctxt) | ||
1965 | { | ||
1966 | debug3("%s: clean up", __func__); | ||
1967 | if (authctxt->methoddata != NULL) { | ||
1968 | jpake_free(authctxt->methoddata); | ||
1969 | authctxt->methoddata = NULL; | ||
1970 | } | ||
1971 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); | ||
1972 | } | ||
1973 | #endif /* JPAKE */ | ||
1974 | |||
1975 | /* find auth method */ | 1684 | /* find auth method */ |
1976 | 1685 | ||
1977 | /* | 1686 | /* |