login.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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, instead emulate
  84. * the behavior of the daemon compiled without PAM support:
  85. * because there can't be any "server password", all
  86. * passwords supplied are classified as "wrong". */
  87. if(Conn_Password(conn)[0] == '\0')
  88. return Login_User_PostAuth(Client);
  89. Client_Reject(Client, "Non-empty password", false);
  90. return DISCONNECTED;
  91. }
  92. if (Conf_PAMIsOptional &&
  93. strcmp(Conn_Password(conn), "") == 0) {
  94. /* Clients are not required to send a password and to be PAM-
  95. * authenticated at all. If not, they won't become "identified"
  96. * and keep the "~" in their supplied user name.
  97. * Therefore it is sensible to either set Conf_PAMisOptional or
  98. * to enable IDENT lookups -- not both. */
  99. return Login_User_PostAuth(Client);
  100. }
  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
  121. /* Check global server password ... */
  122. if (strcmp(Conn_Password(conn), Conf_ServerPwd) != 0) {
  123. /* Bad password! */
  124. Client_Reject(Client, "Bad server password", false);
  125. return DISCONNECTED;
  126. }
  127. return Login_User_PostAuth(Client);
  128. #endif
  129. }
  130. /**
  131. * Finish client registration.
  132. *
  133. * Introduce the new client to the network and send all "hello messages"
  134. * to it after authentication has been succeeded.
  135. *
  136. * @param Client The client logging in.
  137. * @return CONNECTED or DISCONNECTED.
  138. */
  139. GLOBAL bool
  140. Login_User_PostAuth(CLIENT *Client)
  141. {
  142. REQUEST Req;
  143. char modes[CLIENT_MODE_LEN + 1];
  144. assert(Client != NULL);
  145. if (Class_HandleServerBans(Client) != CONNECTED)
  146. return DISCONNECTED;
  147. Client_Introduce(NULL, Client, CLIENT_USER);
  148. if (!IRC_WriteStrClient
  149. (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
  150. return false;
  151. if (!IRC_WriteStrClient
  152. (Client, RPL_YOURHOST_MSG, Client_ID(Client),
  153. Client_ID(Client_ThisServer()), PACKAGE_VERSION, HOST_CPU,
  154. HOST_VENDOR, HOST_OS))
  155. return false;
  156. if (!IRC_WriteStrClient
  157. (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
  158. return false;
  159. if (!IRC_WriteStrClient
  160. (Client, RPL_MYINFO_MSG, Client_ID(Client),
  161. Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
  162. CHANMODES))
  163. return false;
  164. /* Features supported by this server (005 numeric, ISUPPORT),
  165. * see <http://www.irc.org/tech_docs/005.html> for details. */
  166. if (!IRC_Send_ISUPPORT(Client))
  167. return DISCONNECTED;
  168. if (!IRC_Send_LUSERS(Client))
  169. return DISCONNECTED;
  170. if (!IRC_Show_MOTD(Client))
  171. return DISCONNECTED;
  172. /* Set default user modes */
  173. if (Conf_DefaultUserModes[0]) {
  174. snprintf(modes, sizeof(modes), "+%s", Conf_DefaultUserModes);
  175. Req.prefix = Client_ThisServer();
  176. Req.command = "MODE";
  177. Req.argc = 2;
  178. Req.argv[0] = Client_ID(Client);
  179. Req.argv[1] = modes;
  180. IRC_MODE(Client, &Req);
  181. } else
  182. IRC_SetPenalty(Client, 1);
  183. return CONNECTED;
  184. }
  185. #ifdef PAM
  186. /**
  187. * Read result of the authenticator sub-process from pipe
  188. *
  189. * @param r_fd File descriptor of the pipe.
  190. * @param events (ignored IO specification)
  191. */
  192. static void
  193. cb_Read_Auth_Result(int r_fd, UNUSED short events)
  194. {
  195. char user[CLIENT_USER_LEN], *ptr;
  196. CONN_ID conn;
  197. CLIENT *client;
  198. int result;
  199. size_t len;
  200. PROC_STAT *proc;
  201. LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
  202. conn = Conn_GetFromProc(r_fd);
  203. if (conn == NONE) {
  204. /* Ops, none found? Probably the connection has already
  205. * been closed!? We'll ignore that ... */
  206. io_close(r_fd);
  207. LogDebug("Auth: Got callback for unknown connection!?");
  208. return;
  209. }
  210. proc = Conn_GetProcStat(conn);
  211. client = Conn_GetClient(conn);
  212. /* Read result from pipe */
  213. len = Proc_Read(proc, &result, sizeof(result));
  214. Proc_Close(proc);
  215. if (len == 0)
  216. return;
  217. if (len != sizeof(result)) {
  218. Log(LOG_CRIT, "Auth: Got malformed result!");
  219. Client_Reject(client, "Internal error", false);
  220. return;
  221. }
  222. if (result == true) {
  223. /* Authentication succeeded, now set the correct user name
  224. * supplied by the client (without prepended '~' for exmaple),
  225. * but cut it at the first '@' character: */
  226. strlcpy(user, Client_OrigUser(client), sizeof(user));
  227. ptr = strchr(user, '@');
  228. if (ptr)
  229. *ptr = '\0';
  230. Client_SetUser(client, user, true);
  231. (void)Login_User_PostAuth(client);
  232. } else
  233. Client_Reject(client, "Bad password", false);
  234. }
  235. #endif
  236. /* -eof- */