svr-auth.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. * Dropbear - a SSH2 server
  3. *
  4. * Copyright (c) 2002,2003 Matt Johnston
  5. * All rights reserved.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE. */
  24. /* This file (auth.c) handles authentication requests, passing it to the
  25. * particular type (auth-passwd, auth-pubkey). */
  26. #include "includes.h"
  27. #include "dbutil.h"
  28. #include "session.h"
  29. #include "buffer.h"
  30. #include "ssh.h"
  31. #include "packet.h"
  32. #include "auth.h"
  33. #include "runopts.h"
  34. #include "dbrandom.h"
  35. static void authclear(void);
  36. static int checkusername(char *username, unsigned int userlen);
  37. /* initialise the first time for a session, resetting all parameters */
  38. void svr_authinitialise() {
  39. ses.authstate.failcount = 0;
  40. ses.authstate.pw_name = NULL;
  41. ses.authstate.pw_dir = NULL;
  42. ses.authstate.pw_shell = NULL;
  43. ses.authstate.pw_passwd = NULL;
  44. authclear();
  45. }
  46. /* Reset the auth state, but don't reset the failcount. This is for if the
  47. * user decides to try with a different username etc, and is also invoked
  48. * on initialisation */
  49. static void authclear() {
  50. memset(&ses.authstate, 0, sizeof(ses.authstate));
  51. #ifdef ENABLE_SVR_PUBKEY_AUTH
  52. ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
  53. #endif
  54. #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
  55. if (!svr_opts.noauthpass) {
  56. ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
  57. }
  58. #endif
  59. if (ses.authstate.pw_name) {
  60. m_free(ses.authstate.pw_name);
  61. }
  62. if (ses.authstate.pw_shell) {
  63. m_free(ses.authstate.pw_shell);
  64. }
  65. if (ses.authstate.pw_dir) {
  66. m_free(ses.authstate.pw_dir);
  67. }
  68. if (ses.authstate.pw_passwd) {
  69. m_free(ses.authstate.pw_passwd);
  70. }
  71. }
  72. /* Send a banner message if specified to the client. The client might
  73. * ignore this, but possibly serves as a legal "no trespassing" sign */
  74. void send_msg_userauth_banner(buffer *banner) {
  75. TRACE(("enter send_msg_userauth_banner"))
  76. CHECKCLEARTOWRITE();
  77. buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER);
  78. buf_putbufstring(ses.writepayload, banner);
  79. buf_putstring(ses.writepayload, "en", 2);
  80. encrypt_packet();
  81. TRACE(("leave send_msg_userauth_banner"))
  82. }
  83. /* handle a userauth request, check validity, pass to password or pubkey
  84. * checking, and handle success or failure */
  85. void recv_msg_userauth_request() {
  86. char *username = NULL, *servicename = NULL, *methodname = NULL;
  87. unsigned int userlen, servicelen, methodlen;
  88. int valid_user = 0;
  89. TRACE(("enter recv_msg_userauth_request"))
  90. /* ignore packets if auth is already done */
  91. if (ses.authstate.authdone == 1) {
  92. TRACE(("leave recv_msg_userauth_request: authdone already"))
  93. return;
  94. }
  95. /* send the banner if it exists, it will only exist once */
  96. if (svr_opts.banner) {
  97. send_msg_userauth_banner(svr_opts.banner);
  98. buf_free(svr_opts.banner);
  99. svr_opts.banner = NULL;
  100. }
  101. username = buf_getstring(ses.payload, &userlen);
  102. servicename = buf_getstring(ses.payload, &servicelen);
  103. methodname = buf_getstring(ses.payload, &methodlen);
  104. /* only handle 'ssh-connection' currently */
  105. if (servicelen != SSH_SERVICE_CONNECTION_LEN
  106. && (strncmp(servicename, SSH_SERVICE_CONNECTION,
  107. SSH_SERVICE_CONNECTION_LEN) != 0)) {
  108. /* TODO - disconnect here */
  109. m_free(username);
  110. m_free(servicename);
  111. m_free(methodname);
  112. dropbear_exit("unknown service in auth");
  113. }
  114. /* check username is good before continuing.
  115. * the 'incrfail' varies depending on the auth method to
  116. * avoid giving away which users exist on the system through
  117. * the time delay. */
  118. if (checkusername(username, userlen) == DROPBEAR_SUCCESS) {
  119. valid_user = 1;
  120. }
  121. /* user wants to know what methods are supported */
  122. if (methodlen == AUTH_METHOD_NONE_LEN &&
  123. strncmp(methodname, AUTH_METHOD_NONE,
  124. AUTH_METHOD_NONE_LEN) == 0) {
  125. TRACE(("recv_msg_userauth_request: 'none' request"))
  126. if (valid_user
  127. && svr_opts.allowblankpass
  128. && !svr_opts.noauthpass
  129. && !(svr_opts.norootpass && ses.authstate.pw_uid == 0)
  130. && ses.authstate.pw_passwd[0] == '\0')
  131. {
  132. dropbear_log(LOG_NOTICE,
  133. "Auth succeeded with blank password for '%s' from %s",
  134. ses.authstate.pw_name,
  135. svr_ses.addrstring);
  136. send_msg_userauth_success();
  137. goto out;
  138. }
  139. else
  140. {
  141. /* 'none' has no failure delay */
  142. send_msg_userauth_failure(0, 0);
  143. goto out;
  144. }
  145. }
  146. #ifdef ENABLE_SVR_PASSWORD_AUTH
  147. if (!svr_opts.noauthpass &&
  148. !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) {
  149. /* user wants to try password auth */
  150. if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
  151. strncmp(methodname, AUTH_METHOD_PASSWORD,
  152. AUTH_METHOD_PASSWORD_LEN) == 0) {
  153. if (valid_user) {
  154. svr_auth_password();
  155. goto out;
  156. }
  157. }
  158. }
  159. #endif
  160. #ifdef ENABLE_SVR_PAM_AUTH
  161. if (!svr_opts.noauthpass &&
  162. !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) {
  163. /* user wants to try password auth */
  164. if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
  165. strncmp(methodname, AUTH_METHOD_PASSWORD,
  166. AUTH_METHOD_PASSWORD_LEN) == 0) {
  167. if (valid_user) {
  168. svr_auth_pam();
  169. goto out;
  170. }
  171. }
  172. }
  173. #endif
  174. #ifdef ENABLE_SVR_PUBKEY_AUTH
  175. /* user wants to try pubkey auth */
  176. if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
  177. strncmp(methodname, AUTH_METHOD_PUBKEY,
  178. AUTH_METHOD_PUBKEY_LEN) == 0) {
  179. if (valid_user) {
  180. svr_auth_pubkey();
  181. } else {
  182. /* pubkey has no failure delay */
  183. send_msg_userauth_failure(0, 0);
  184. }
  185. goto out;
  186. }
  187. #endif
  188. /* nothing matched, we just fail with a delay */
  189. send_msg_userauth_failure(0, 1);
  190. out:
  191. m_free(username);
  192. m_free(servicename);
  193. m_free(methodname);
  194. }
  195. /* Check that the username exists and isn't disallowed (root), and has a valid shell.
  196. * returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
  197. static int checkusername(char *username, unsigned int userlen) {
  198. char* listshell = NULL;
  199. char* usershell = NULL;
  200. uid_t uid;
  201. TRACE(("enter checkusername"))
  202. if (userlen > MAX_USERNAME_LEN) {
  203. return DROPBEAR_FAILURE;
  204. }
  205. /* new user or username has changed */
  206. if (ses.authstate.username == NULL ||
  207. strcmp(username, ses.authstate.username) != 0) {
  208. /* the username needs resetting */
  209. if (ses.authstate.username != NULL) {
  210. dropbear_log(LOG_WARNING, "Client trying multiple usernames from %s",
  211. svr_ses.addrstring);
  212. m_free(ses.authstate.username);
  213. }
  214. authclear();
  215. fill_passwd(username);
  216. ses.authstate.username = m_strdup(username);
  217. }
  218. /* check that user exists */
  219. if (!ses.authstate.pw_name) {
  220. TRACE(("leave checkusername: user '%s' doesn't exist", username))
  221. dropbear_log(LOG_WARNING,
  222. "Login attempt for nonexistent user from %s",
  223. svr_ses.addrstring);
  224. return DROPBEAR_FAILURE;
  225. }
  226. /* check if we are running as non-root, and login user is different from the server */
  227. uid = geteuid();
  228. if (uid != 0 && uid != ses.authstate.pw_uid) {
  229. TRACE(("running as nonroot, only server uid is allowed"))
  230. dropbear_log(LOG_WARNING,
  231. "Login attempt with wrong user %s from %s",
  232. ses.authstate.pw_name,
  233. svr_ses.addrstring);
  234. return DROPBEAR_FAILURE;
  235. }
  236. /* check for non-root if desired */
  237. if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) {
  238. TRACE(("leave checkusername: root login disabled"))
  239. dropbear_log(LOG_WARNING, "root login rejected");
  240. return DROPBEAR_FAILURE;
  241. }
  242. TRACE(("shell is %s", ses.authstate.pw_shell))
  243. /* check that the shell is set */
  244. usershell = ses.authstate.pw_shell;
  245. if (usershell[0] == '\0') {
  246. /* empty shell in /etc/passwd means /bin/sh according to passwd(5) */
  247. usershell = "/bin/sh";
  248. }
  249. /* check the shell is valid. If /etc/shells doesn't exist, getusershell()
  250. * should return some standard shells like "/bin/sh" and "/bin/csh" (this
  251. * is platform-specific) */
  252. setusershell();
  253. while ((listshell = getusershell()) != NULL) {
  254. TRACE(("test shell is '%s'", listshell))
  255. if (strcmp(listshell, usershell) == 0) {
  256. /* have a match */
  257. goto goodshell;
  258. }
  259. }
  260. /* no matching shell */
  261. endusershell();
  262. TRACE(("no matching shell"))
  263. dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
  264. ses.authstate.pw_name);
  265. return DROPBEAR_FAILURE;
  266. goodshell:
  267. endusershell();
  268. TRACE(("matching shell"))
  269. TRACE(("uid = %d", ses.authstate.pw_uid))
  270. TRACE(("leave checkusername"))
  271. return DROPBEAR_SUCCESS;
  272. }
  273. /* Send a failure message to the client, in responds to a userauth_request.
  274. * Partial indicates whether to set the "partial success" flag,
  275. * incrfail is whether to count this failure in the failure count (which
  276. * is limited. This function also handles disconnection after too many
  277. * failures */
  278. void send_msg_userauth_failure(int partial, int incrfail) {
  279. buffer *typebuf = NULL;
  280. TRACE(("enter send_msg_userauth_failure"))
  281. CHECKCLEARTOWRITE();
  282. buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_FAILURE);
  283. /* put a list of allowed types */
  284. typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */
  285. if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
  286. buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
  287. if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
  288. buf_putbyte(typebuf, ',');
  289. }
  290. }
  291. if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
  292. buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
  293. }
  294. buf_putbufstring(ses.writepayload, typebuf);
  295. TRACE(("auth fail: methods %d, '%.*s'", ses.authstate.authtypes,
  296. typebuf->len, typebuf->data))
  297. buf_free(typebuf);
  298. buf_putbyte(ses.writepayload, partial ? 1 : 0);
  299. encrypt_packet();
  300. if (incrfail) {
  301. unsigned int delay;
  302. genrandom((unsigned char*)&delay, sizeof(delay));
  303. /* We delay for 300ms +- 50ms */
  304. delay = 250000 + (delay % 100000);
  305. usleep(delay);
  306. ses.authstate.failcount++;
  307. }
  308. if (ses.authstate.failcount >= MAX_AUTH_TRIES) {
  309. char * userstr;
  310. /* XXX - send disconnect ? */
  311. TRACE(("Max auth tries reached, exiting"))
  312. if (ses.authstate.pw_name == NULL) {
  313. userstr = "is invalid";
  314. } else {
  315. userstr = ses.authstate.pw_name;
  316. }
  317. dropbear_exit("Max auth tries reached - user '%s' from %s",
  318. userstr, svr_ses.addrstring);
  319. }
  320. TRACE(("leave send_msg_userauth_failure"))
  321. }
  322. /* Send a success message to the user, and set the "authdone" flag */
  323. void send_msg_userauth_success() {
  324. TRACE(("enter send_msg_userauth_success"))
  325. CHECKCLEARTOWRITE();
  326. buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS);
  327. encrypt_packet();
  328. /* authdone must be set after encrypt_packet() for
  329. * delayed-zlib mode */
  330. ses.authstate.authdone = 1;
  331. ses.connect_time = 0;
  332. if (ses.authstate.pw_uid == 0) {
  333. ses.allowprivport = 1;
  334. }
  335. /* Remove from the list of pre-auth sockets. Should be m_close(), since if
  336. * we fail, we might end up leaking connection slots, and disallow new
  337. * logins - a nasty situation. */
  338. m_close(svr_ses.childpipe);
  339. TRACE(("leave send_msg_userauth_success"))
  340. }