login.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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(Conn_Password(conn)[0] == '\0')
  86. return Login_User_PostAuth(Client);
  87. Client_Reject(Client, "Non-empty password", false);
  88. return DISCONNECTED;
  89. }
  90. if (Conf_PAMIsOptional &&
  91. strcmp(Conn_Password(conn), "") == 0) {
  92. /* Clients are not required to send a password and to be PAM-
  93. * authenticated at all. If not, they won't become "identified"
  94. * and keep the "~" in their supplied user name.
  95. * Therefore it is sensible to either set Conf_PAMisOptional or
  96. * to enable IDENT lookups -- not both. */
  97. return Login_User_PostAuth(Client);
  98. }
  99. /* Fork child process for PAM authentication; and make sure that the
  100. * process timeout is set higher than the login timeout! */
  101. pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
  102. cb_Read_Auth_Result, Conf_PongTimeout + 1);
  103. if (pid > 0) {
  104. LogDebug("Authenticator for connection %d created (PID %d).",
  105. conn, pid);
  106. return CONNECTED;
  107. } else {
  108. /* Sub process */
  109. Log_Init_Subprocess("Auth");
  110. Conn_CloseAllSockets(NONE);
  111. result = PAM_Authenticate(Client);
  112. if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
  113. Log_Subprocess(LOG_ERR,
  114. "Failed to pipe result to parent!");
  115. Log_Exit_Subprocess("Auth");
  116. exit(0);
  117. }
  118. #else
  119. /* Check global server password ... */
  120. if (strcmp(Conn_Password(conn), Conf_ServerPwd) != 0) {
  121. /* Bad password! */
  122. Client_Reject(Client, "Bad server password", false);
  123. return DISCONNECTED;
  124. }
  125. return Login_User_PostAuth(Client);
  126. #endif
  127. }
  128. /**
  129. * Finish client registration.
  130. *
  131. * Introduce the new client to the network and send all "hello messages"
  132. * to it after authentication has been succeeded.
  133. *
  134. * @param Client The client logging in.
  135. * @return CONNECTED or DISCONNECTED.
  136. */
  137. GLOBAL bool
  138. Login_User_PostAuth(CLIENT *Client)
  139. {
  140. assert(Client != NULL);
  141. if (Class_HandleServerBans(Client) != CONNECTED)
  142. return DISCONNECTED;
  143. Client_Introduce(NULL, Client, CLIENT_USER);
  144. if (!IRC_WriteStrClient
  145. (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
  146. return false;
  147. if (!IRC_WriteStrClient
  148. (Client, RPL_YOURHOST_MSG, Client_ID(Client),
  149. Client_ID(Client_ThisServer()), PACKAGE_VERSION, HOST_CPU,
  150. HOST_VENDOR, HOST_OS))
  151. return false;
  152. if (!IRC_WriteStrClient
  153. (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
  154. return false;
  155. if (!IRC_WriteStrClient
  156. (Client, RPL_MYINFO_MSG, Client_ID(Client),
  157. Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
  158. CHANMODES))
  159. return false;
  160. /* Features supported by this server (005 numeric, ISUPPORT),
  161. * see <http://www.irc.org/tech_docs/005.html> for details. */
  162. if (!IRC_Send_ISUPPORT(Client))
  163. return DISCONNECTED;
  164. if (!IRC_Send_LUSERS(Client))
  165. return DISCONNECTED;
  166. if (!IRC_Show_MOTD(Client))
  167. return DISCONNECTED;
  168. /* Suspend the client for a second ... */
  169. IRC_SetPenalty(Client, 1);
  170. return CONNECTED;
  171. }
  172. #ifdef PAM
  173. /**
  174. * Read result of the authenticatior sub-process from pipe
  175. *
  176. * @param r_fd File descriptor of the pipe.
  177. * @param events (ignored IO specification)
  178. */
  179. static void
  180. cb_Read_Auth_Result(int r_fd, UNUSED short events)
  181. {
  182. CONN_ID conn;
  183. CLIENT *client;
  184. int result;
  185. size_t len;
  186. PROC_STAT *proc;
  187. LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
  188. conn = Conn_GetFromProc(r_fd);
  189. if (conn == NONE) {
  190. /* Ops, none found? Probably the connection has already
  191. * been closed!? We'll ignore that ... */
  192. io_close(r_fd);
  193. LogDebug("Auth: Got callback for unknown connection!?");
  194. return;
  195. }
  196. proc = Conn_GetProcStat(conn);
  197. client = Conn_GetClient(conn);
  198. /* Read result from pipe */
  199. len = Proc_Read(proc, &result, sizeof(result));
  200. Proc_Close(proc);
  201. if (len == 0)
  202. return;
  203. if (len != sizeof(result)) {
  204. Log(LOG_CRIT, "Auth: Got malformed result!");
  205. Client_Reject(client, "Internal error", false);
  206. return;
  207. }
  208. if (result == true) {
  209. Client_SetUser(client, Client_OrigUser(client), true);
  210. (void)Login_User_PostAuth(client);
  211. } else
  212. Client_Reject(client, "Bad password", false);
  213. }
  214. #endif
  215. /* -eof- */