login.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * Please read the file COPYING, README and AUTHORS for more information.
  10. */
  11. #include "portab.h"
  12. /**
  13. * @file
  14. * Functions to deal with client logins
  15. */
  16. #include "imp.h"
  17. #include <assert.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <strings.h>
  21. #include <unistd.h>
  22. #include "defines.h"
  23. #include "conn.h"
  24. #include "class.h"
  25. #include "client.h"
  26. #include "client-cap.h"
  27. #include "channel.h"
  28. #include "conf.h"
  29. #include "io.h"
  30. #include "parse.h"
  31. #include "log.h"
  32. #include "messages.h"
  33. #include "ngircd.h"
  34. #include "pam.h"
  35. #include "irc-info.h"
  36. #include "irc-write.h"
  37. #include "exp.h"
  38. #include "login.h"
  39. #ifdef PAM
  40. static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events));
  41. #endif
  42. /**
  43. * Initiate client login.
  44. *
  45. * This function is called after the daemon received the required NICK and
  46. * USER commands of a new client. If the daemon is compiled with support for
  47. * PAM, the authentication sub-processs is forked; otherwise the global server
  48. * password is checked.
  49. *
  50. * @param Client The client logging in.
  51. * @returns CONNECTED or DISCONNECTED.
  52. */
  53. GLOBAL bool
  54. Login_User(CLIENT * Client)
  55. {
  56. #ifdef PAM
  57. int pipefd[2], result;
  58. pid_t pid;
  59. #endif
  60. CONN_ID conn;
  61. assert(Client != NULL);
  62. conn = Client_Conn(Client);
  63. #ifndef STRICT_RFC
  64. if (Conf_AuthPing) {
  65. /* Did we receive the "auth PONG" already? */
  66. if (Conn_GetAuthPing(conn)) {
  67. Client_SetType(Client, CLIENT_WAITAUTHPING);
  68. LogDebug("Connection %d: Waiting for AUTH PONG ...", conn);
  69. return CONNECTED;
  70. }
  71. }
  72. #endif
  73. /* Still waiting for "CAP END" command? */
  74. if (Client_Cap(Client) & CLIENT_CAP_PENDING) {
  75. Client_SetType(Client, CLIENT_WAITCAPEND);
  76. LogDebug("Connection %d: Waiting for CAP END ...", conn);
  77. return CONNECTED;
  78. }
  79. #ifdef PAM
  80. if (!Conf_PAM) {
  81. /* Don't do any PAM authentication at all, instead emulate
  82. * the beahiour of the daemon compiled without PAM support:
  83. * because there can't be any "server password", all
  84. * passwords supplied are classified as "wrong". */
  85. if(Client_Password(Client)[0] == '\0')
  86. return Login_User_PostAuth(Client);
  87. Client_Reject(Client, "Non-empty password", false);
  88. return DISCONNECTED;
  89. }
  90. if (Conf_PAMIsOptional && strcmp(Client_Password(Client), "") == 0) {
  91. /* Clients are not required to send a password and to be PAM-
  92. * authenticated at all. If not, they won't become "identified"
  93. * and keep the "~" in their supplied user name.
  94. * Therefore it is sensible to either set Conf_PAMisOptional or
  95. * to enable IDENT lookups -- not both. */
  96. return Login_User_PostAuth(Client);
  97. }
  98. /* Fork child process for PAM authentication; and make sure that the
  99. * process timeout is set higher than the login timeout! */
  100. pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
  101. cb_Read_Auth_Result, Conf_PongTimeout + 1);
  102. if (pid > 0) {
  103. LogDebug("Authenticator for connection %d created (PID %d).",
  104. conn, pid);
  105. return CONNECTED;
  106. } else {
  107. /* Sub process */
  108. Log_Init_Subprocess("Auth");
  109. Conn_CloseAllSockets(NONE);
  110. result = PAM_Authenticate(Client);
  111. if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
  112. Log_Subprocess(LOG_ERR,
  113. "Failed to pipe result to parent!");
  114. Log_Exit_Subprocess("Auth");
  115. exit(0);
  116. }
  117. #else
  118. /* Check global server password ... */
  119. if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
  120. /* Bad password! */
  121. Client_Reject(Client, "Bad server password", false);
  122. return DISCONNECTED;
  123. }
  124. return Login_User_PostAuth(Client);
  125. #endif
  126. }
  127. /**
  128. * Finish client registration.
  129. *
  130. * Introduce the new client to the network and send all "hello messages"
  131. * to it after authentication has been succeeded.
  132. *
  133. * @param Client The client logging in.
  134. * @return CONNECTED or DISCONNECTED.
  135. */
  136. GLOBAL bool
  137. Login_User_PostAuth(CLIENT *Client)
  138. {
  139. assert(Client != NULL);
  140. if (Class_HandleServerBans(Client) != CONNECTED)
  141. return DISCONNECTED;
  142. Client_Introduce(NULL, Client, CLIENT_USER);
  143. if (!IRC_WriteStrClient
  144. (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
  145. return false;
  146. if (!IRC_WriteStrClient
  147. (Client, RPL_YOURHOST_MSG, Client_ID(Client),
  148. Client_ID(Client_ThisServer()), PACKAGE_VERSION, TARGET_CPU,
  149. TARGET_VENDOR, TARGET_OS))
  150. return false;
  151. if (!IRC_WriteStrClient
  152. (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
  153. return false;
  154. if (!IRC_WriteStrClient
  155. (Client, RPL_MYINFO_MSG, Client_ID(Client),
  156. Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
  157. CHANMODES))
  158. return false;
  159. /* Features supported by this server (005 numeric, ISUPPORT),
  160. * see <http://www.irc.org/tech_docs/005.html> for details. */
  161. if (!IRC_Send_ISUPPORT(Client))
  162. return DISCONNECTED;
  163. if (!IRC_Send_LUSERS(Client))
  164. return DISCONNECTED;
  165. if (!IRC_Show_MOTD(Client))
  166. return DISCONNECTED;
  167. /* Suspend the client for a second ... */
  168. IRC_SetPenalty(Client, 1);
  169. return CONNECTED;
  170. }
  171. #ifdef PAM
  172. /**
  173. * Read result of the authenticatior sub-process from pipe
  174. *
  175. * @param r_fd File descriptor of the pipe.
  176. * @param events (ignored IO specification)
  177. */
  178. static void
  179. cb_Read_Auth_Result(int r_fd, UNUSED short events)
  180. {
  181. CONN_ID conn;
  182. CLIENT *client;
  183. int result;
  184. size_t len;
  185. PROC_STAT *proc;
  186. LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
  187. conn = Conn_GetFromProc(r_fd);
  188. if (conn == NONE) {
  189. /* Ops, none found? Probably the connection has already
  190. * been closed!? We'll ignore that ... */
  191. io_close(r_fd);
  192. LogDebug("Auth: Got callback for unknown connection!?");
  193. return;
  194. }
  195. proc = Conn_GetProcStat(conn);
  196. client = Conn_GetClient(conn);
  197. /* Read result from pipe */
  198. len = Proc_Read(proc, &result, sizeof(result));
  199. Proc_Close(proc);
  200. if (len == 0)
  201. return;
  202. if (len != sizeof(result)) {
  203. Log(LOG_CRIT, "Auth: Got malformed result!");
  204. Client_Reject(client, "Internal error", false);
  205. return;
  206. }
  207. if (result == true) {
  208. Client_SetUser(client, Client_OrigUser(client), true);
  209. (void)Login_User_PostAuth(client);
  210. } else
  211. Client_Reject(client, "Bad password", false);
  212. }
  213. #endif
  214. /* -eof- */