login.c 6.9 KB

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