login.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2014 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 <assert.h>
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include "conn.h"
  22. #include "class.h"
  23. #include "client-cap.h"
  24. #include "channel.h"
  25. #include "conf.h"
  26. #include "parse.h"
  27. #include "log.h"
  28. #include "messages.h"
  29. #include "ngircd.h"
  30. #include "irc-info.h"
  31. #include "irc-mode.h"
  32. #include "irc-write.h"
  33. #include "login.h"
  34. #ifdef PAM
  35. #include "io.h"
  36. #include "pam.h"
  37. static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events));
  38. #endif
  39. /**
  40. * Initiate client login.
  41. *
  42. * This function is called after the daemon received the required NICK and
  43. * USER commands of a new client. If the daemon is compiled with support for
  44. * PAM, the authentication sub-processs is forked; otherwise the global server
  45. * password is checked.
  46. *
  47. * @param Client The client logging in.
  48. * @returns CONNECTED or DISCONNECTED.
  49. */
  50. GLOBAL bool
  51. Login_User(CLIENT * Client)
  52. {
  53. #ifdef PAM
  54. int pipefd[2], result;
  55. pid_t pid;
  56. #endif
  57. CONN_ID conn;
  58. assert(Client != NULL);
  59. conn = Client_Conn(Client);
  60. #ifndef STRICT_RFC
  61. if (Conf_AuthPing) {
  62. /* Did we receive the "auth PONG" already? */
  63. if (Conn_GetAuthPing(conn)) {
  64. Client_SetType(Client, CLIENT_WAITAUTHPING);
  65. LogDebug("Connection %d: Waiting for AUTH PONG ...", conn);
  66. return CONNECTED;
  67. }
  68. }
  69. #endif
  70. /* Still waiting for "CAP END" command? */
  71. if (Client_Cap(Client) & CLIENT_CAP_PENDING) {
  72. Client_SetType(Client, CLIENT_WAITCAPEND);
  73. LogDebug("Connection %d: Waiting for CAP END ...", conn);
  74. return CONNECTED;
  75. }
  76. #ifdef PAM
  77. if (!Conf_PAM) {
  78. /* Don't do any PAM authentication at all if PAM is not
  79. * enabled, instead emulate the behavior of the daemon
  80. * compiled without PAM support. */
  81. if (strcmp(Conn_Password(conn), Conf_ServerPwd) == 0)
  82. return Login_User_PostAuth(Client);
  83. Client_Reject(Client, "Bad server password", false);
  84. return DISCONNECTED;
  85. }
  86. if (Conf_PAMIsOptional &&
  87. strcmp(Conn_Password(conn), "") == 0) {
  88. /* Clients are not required to send a password and to be PAM-
  89. * authenticated at all. If not, they won't become "identified"
  90. * and keep the "~" in their supplied user name.
  91. * Therefore it is sensible to either set Conf_PAMisOptional or
  92. * to enable IDENT lookups -- not both. */
  93. return Login_User_PostAuth(Client);
  94. }
  95. if (Conf_PAM) {
  96. /* Fork child process for PAM authentication; and make sure that the
  97. * process timeout is set higher than the login timeout! */
  98. pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
  99. cb_Read_Auth_Result, Conf_PongTimeout + 1);
  100. if (pid > 0) {
  101. LogDebug("Authenticator for connection %d created (PID %d).",
  102. conn, pid);
  103. return CONNECTED;
  104. } else {
  105. /* Sub process */
  106. Log_Init_Subprocess("Auth");
  107. Conn_CloseAllSockets(NONE);
  108. result = PAM_Authenticate(Client);
  109. if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
  110. Log_Subprocess(LOG_ERR,
  111. "Failed to pipe result to parent!");
  112. Log_Exit_Subprocess("Auth");
  113. exit(0);
  114. }
  115. } else return CONNECTED;
  116. #else
  117. /* Check global server password ... */
  118. if (strcmp(Conn_Password(conn), Conf_ServerPwd) != 0) {
  119. /* Bad password! */
  120. Client_Reject(Client, "Bad server password", false);
  121. return DISCONNECTED;
  122. }
  123. return Login_User_PostAuth(Client);
  124. #endif
  125. }
  126. /**
  127. * Finish client registration.
  128. *
  129. * Introduce the new client to the network and send all "hello messages"
  130. * to it after authentication has been succeeded.
  131. *
  132. * @param Client The client logging in.
  133. * @return CONNECTED or DISCONNECTED.
  134. */
  135. GLOBAL bool
  136. Login_User_PostAuth(CLIENT *Client)
  137. {
  138. REQUEST Req;
  139. char modes[CLIENT_MODE_LEN + 1];
  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. /* Set default user modes */
  169. if (Conf_DefaultUserModes[0]) {
  170. snprintf(modes, sizeof(modes), "+%s", Conf_DefaultUserModes);
  171. Req.prefix = Client_ID(Client_ThisServer());
  172. Req.command = "MODE";
  173. Req.argc = 2;
  174. Req.argv[0] = Client_ID(Client);
  175. Req.argv[1] = modes;
  176. IRC_MODE(Client, &Req);
  177. } else
  178. IRC_SetPenalty(Client, 1);
  179. return CONNECTED;
  180. }
  181. #ifdef PAM
  182. /**
  183. * Read result of the authenticator sub-process from pipe
  184. *
  185. * @param r_fd File descriptor of the pipe.
  186. * @param events (ignored IO specification)
  187. */
  188. static void
  189. cb_Read_Auth_Result(int r_fd, UNUSED short events)
  190. {
  191. char user[CLIENT_USER_LEN], *ptr;
  192. CONN_ID conn;
  193. CLIENT *client;
  194. int result;
  195. size_t len;
  196. PROC_STAT *proc;
  197. LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
  198. conn = Conn_GetFromProc(r_fd);
  199. if (conn == NONE) {
  200. /* Ops, none found? Probably the connection has already
  201. * been closed!? We'll ignore that ... */
  202. io_close(r_fd);
  203. LogDebug("Auth: Got callback for unknown connection!?");
  204. return;
  205. }
  206. proc = Conn_GetProcStat(conn);
  207. client = Conn_GetClient(conn);
  208. /* Read result from pipe */
  209. len = Proc_Read(proc, &result, sizeof(result));
  210. Proc_Close(proc);
  211. if (len == 0)
  212. return;
  213. if (len != sizeof(result)) {
  214. Log(LOG_CRIT, "Auth: Got malformed result!");
  215. Client_Reject(client, "Internal error", false);
  216. return;
  217. }
  218. if (result == true) {
  219. /* Authentication succeeded, now set the correct user name
  220. * supplied by the client (without prepended '~' for exmaple),
  221. * but cut it at the first '@' character: */
  222. strlcpy(user, Client_OrigUser(client), sizeof(user));
  223. ptr = strchr(user, '@');
  224. if (ptr)
  225. *ptr = '\0';
  226. Client_SetUser(client, user, true);
  227. (void)Login_User_PostAuth(client);
  228. } else
  229. Client_Reject(client, "Bad password", false);
  230. }
  231. #endif
  232. /* -eof- */