1 /* vi:ai:et:ts=8 sw=2
2 */
3 /*
4 * wzdftpd - a modular and cool ftp server
5 * Copyright (C) 2002-2004 Pierre Chifflier
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * As a special exemption, Pierre Chifflier
22 * and other respective copyright holders give permission to link this program
23 * with OpenSSL, and distribute the resulting executable, without including
24 * the source code for OpenSSL in the source distribution.
25 */
26
27 /** \file wzd_login.c
28 * \brief Login sequence
29 */
30
31 #include "wzd_all.h"
32
33 #ifndef WZD_USE_PCH
34
35 #ifdef WIN32
36 #include <winsock2.h>
37 #include <ws2tcpip.h>
38 #else
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h> /* struct in_addr (wzd_misc.h) */
43
44 #include <netdb.h>
45 #endif
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <sys/stat.h>
51
52 #include "wzd_structs.h"
53
54 #include "wzd_ClientThread.h"
55 #include "wzd_configfile.h"
56 #include "wzd_group.h"
57 #include "wzd_ip.h"
58 #include "wzd_log.h"
59 #include "wzd_login.h"
60 #include "wzd_messages.h"
61 #include "wzd_misc.h"
62 #include "wzd_protocol.h"
63 #include "wzd_socket.h"
64 #include "wzd_tls.h"
65 #include "wzd_user.h"
66
67 #include <libwzd-auth/wzd_krb5.h>
68
69 #include "wzd_debug.h"
70
71 #endif /* WZD_USE_PCH */
72
73 #define BUFFER_LEN 4096
74
75 static int check_tls_forced(wzd_context_t * context);
76
77 #if defined (HAVE_KRB5)
78 static int do_login_gssapi(wzd_context_t * context);
79 #endif
80
81 /*************** do_user *****************************/
82 /** \brief Check username
83 *
84 * The following checks are performed:
85 * - check if a backlend validates the username
86 * - check if the user is not marked as deleted
87 * - check if site is not closed
88 * - check if maximum number of logins for user or
89 * his groups has been reached
90 * - check if TLS is enforced but not enabled
91 *
92 * \return E_OK if ok
93 * E_USER_REJECTED if user name is rejected by backend
94 * E_USER_DELETED if user has been deleted
95 * E_USER_NUMLOGINS if user has reached num_logins
96 * E_USER_CLOSED if site is closed and user is not a siteop
97 * E_USER_TLSFORCED if user must use SSL/TLS
98 * E_GROUP_NUMLOGINS if user has reached group num_logins
99 */
do_user(const char * username,wzd_context_t * context)100 int do_user(const char *username, wzd_context_t * context)
101 {
102 int ret;
103 wzd_user_t * me;
104
105 me = NULL;
106
107 ret = backend_validate_login(username,me,&context->userid);
108 if (ret) return E_USER_REJECTED;
109
110 me = GetUserByID(context->userid);
111 if (!me) return E_USER_IDONTEXIST;
112
113 /* check if user have been deleted */
114 if (me->flags && strchr(me->flags,FLAG_DELETED))
115 return E_USER_DELETED;
116
117 /* check if site is closed */
118 if (mainConfig->site_closed &&
119 !(me->flags && strchr(me->flags,FLAG_SITEOP)))
120 return E_USER_CLOSED;
121
122 /* count logins from user */
123 if (me->num_logins)
124 {
125 ListElmt * elmnt;
126 wzd_context_t * loop_context;
127 int count=0;
128 for (elmnt=list_head(context_list); elmnt!=NULL; elmnt=list_next(elmnt))
129 {
130 loop_context = list_data(elmnt);
131 if (loop_context && loop_context->magic == CONTEXT_MAGIC && context->userid == loop_context->userid)
132 count++;
133 } /* for all contexts */
134
135 /* we substract 1, because the current login attempt is counted */
136 count--;
137
138 /* out_err(LEVEL_CRITICAL,"NUM_logins: %d\n",count);*/
139
140 if (count >= me->num_logins) return E_USER_NUMLOGINS;
141 /* >= and not ==, because it two attempts are issued simultaneously, count > num_logins ! */
142 }
143
144 /* foreach group of user, check num_logins */
145 {
146 ListElmt * elmnt;
147 wzd_context_t * loop_context;
148 unsigned int i,j,k;
149 wzd_group_t * group;
150 wzd_user_t * user;
151 unsigned int * num_logins;
152
153 num_logins = malloc(me->group_num * sizeof(unsigned int));
154 memset(num_logins,0,me->group_num*sizeof(int));
155 /* try to do it in one pass only */
156 /* we build the same tab as me->groups, containing the counters */
157 for (elmnt=list_head(context_list); elmnt!=NULL; elmnt=list_next(elmnt))
158 {
159 loop_context = list_data(elmnt);
160 if (loop_context && loop_context->magic == CONTEXT_MAGIC) {
161 user = GetUserByID(loop_context->userid);
162 if (!user) {
163 /* this can happen if a user disconnects while iterating list */
164 continue;
165 }
166 for (j=0; j<user->group_num; j++)
167 for (k=0; k<me->group_num; k++)
168 if (user->groups[j] == me->groups[k])
169 num_logins[ k ]++;
170 }
171 }
172 /* checks num_logins for all groups */
173 for (i=0; i<me->group_num; i++)
174 {
175 group = GetGroupByID( me->groups[i] );
176 if (group && group->num_logins
177 && (num_logins[i]>group->num_logins))
178 /* > and not >= because current login attempt is counted ! */
179 {
180 free(num_logins);
181 return E_GROUP_NUMLOGINS; /* user has reached group max num_logins */
182 }
183 }
184 free(num_logins);
185 }
186
187 /* Check for TLS enforce here, before pass was sent to server */
188 if (check_tls_forced(context))
189 return E_USER_TLSFORCED;
190
191 return E_OK;
192 }
193
194
195 /*************** do_pass *****************************/
196 /** \brief Check password (or authentication method)
197 *
198 * The following checks are performed:
199 * - user exists and has not been deleted
200 * - the backend validates the password or authentication method
201 * - home directory exists, and user can enter directory
202 *
203 * \return E_OK if ok
204 * E_USER_REJECTED if user does not exist
205 * E_PASS_REJECTED if wrong pass
206 * E_USER_DELETED if user has been deleted
207 * E_LOGIN_NO_HOME if ok but homedir does not exist */
do_pass(const char * username,const char * pass,wzd_context_t * context)208 int do_pass(const char *username, const char * pass, wzd_context_t * context)
209 {
210 /* char buffer[4096];*/
211 int ret;
212 wzd_user_t * user;
213
214 user = GetUserByID(context->userid);
215 if (user == NULL) return E_USER_REJECTED;
216
217 /* check if user have been deleted */
218 if (user->flags && strchr(user->flags,FLAG_DELETED))
219 return E_USER_DELETED;
220
221 ret = backend_validate_pass(username,pass,NULL,&context->userid);
222 if (ret) {
223 /* pass was not accepted */
224 return E_PASS_REJECTED;
225 }
226
227 /* normalize rootpath */
228
229 /* if (!realpath(context->userinfo.rootpath,buffer)) return 1;
230 strncpy(context->userinfo.rootpath,buffer,1024);*/
231
232 /* initial dir */
233 strcpy(context->currentpath,"/");
234 #ifdef WIN32
235 if (strchr(user->flags,FLAG_FULLPATH) ) strcat(context->currentpath,user->rootpath);
236 #endif
237 if (do_chdir(context->currentpath,context))
238 {
239 /* could not chdir to home !!!! */
240 out_log(LEVEL_CRITICAL,"Could not chdir to home '%s' (root: '%s'), user '%s'\n",context->currentpath,user->rootpath,user->username);
241 return E_USER_NO_HOME;
242 }
243
244 /* XXX - now we can wait (or not) the ACCT */
245
246 return E_OK;
247 }
248
249
250 /*************** do_user_ip **************************/
251 /** \brief Check if user is connecting from an authorized ip
252 *
253 * IP addresses are checked in user list first, then in all of
254 * its groups.
255 *
256 * Checks are stopped at the first match.
257 */
do_user_ip(const char * username,wzd_context_t * context)258 int do_user_ip(const char *username, wzd_context_t * context)
259 {
260 char ip[INET6_ADDRSTRLEN];
261 const char *userip = (const char*)context->hostip;
262 wzd_user_t * user;
263 wzd_group_t *group;
264 unsigned int i;
265 int ret;
266
267 user = GetUserByID(context->userid);
268
269 if (!user) {
270 int reject_nonexistant = 0;
271 if (CFG_GET_OPTION(mainConfig,CFG_OPT_REJECT_UNKNOWN_USERS))
272 reject_nonexistant = 1;
273 if (!reject_nonexistant) return E_OK;
274 return E_USER_IDONTEXIST;
275 }
276
277 #if defined(IPV6_SUPPORT)
278 if (context->family == WZD_INET6) {
279 inet_ntop(AF_INET6,userip,ip,INET6_ADDRSTRLEN);
280 } else
281 #endif
282 {
283 inet_ntop(AF_INET,userip,ip,INET_ADDRSTRLEN);
284 }
285
286 ret = ip_list_check_ident(user->ip_list, ip, context->ident);
287 if (ret > 0) return E_OK;
288
289 /* user ip not found, try groups */
290 for (i=0; i<user->group_num; i++) {
291 group = GetGroupByID(user->groups[i]);
292 if (ip_list_check_ident(group->ip_list, ip, context->ident)==1)
293 return E_OK;
294 }
295
296 return E_USER_NOIP;
297 }
298
299
300 /*************** do_login_loop ***********************/
do_login_loop(wzd_context_t * context)301 static int do_login_loop(wzd_context_t * context)
302 {
303 char buffer[BUFFER_LEN];
304 char * ptr;
305 char * token;
306 char username[HARD_USERNAME_LENGTH];
307 int ret;
308 int user_ok=0, pass_ok=0;
309 int reject_nonexistant=0;
310 #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
311 int tls_ok=0;
312 #endif
313 int command;
314
315 if (CFG_GET_OPTION(mainConfig,CFG_OPT_REJECT_UNKNOWN_USERS))
316 reject_nonexistant = 1;
317
318 *username = '\0';
319
320 context->state = STATE_LOGGING;
321
322 while (1) {
323 /* wait response */
324 ret = (context->read_fct)(context->controlfd,buffer,BUFFER_LEN,0,HARD_XFER_TIMEOUT,context);
325
326 if (ret == 0) {
327 out_err(LEVEL_FLOOD,"Connection closed or timeout (socket %d)\n",context->controlfd);
328 return 1;
329 }
330 if (ret==-1) {
331 out_err(LEVEL_FLOOD,"Error reading client response (socket %d)\n",context->controlfd);
332 return 1;
333 }
334
335 /* this replace the memset (bzero ?) some lines before */
336 buffer[ret-1] = '\0';
337
338 if (buffer[0]=='\0') continue;
339
340 {
341 size_t length = strlen(buffer);
342 while (length > 0 && (buffer[length-1]=='\r' || buffer[length-1]=='\n'))
343 buffer[length-- -1] = '\0';
344 set_action(context,buffer);
345 }
346
347 #ifdef DEBUG
348 out_err(LEVEL_FLOOD,"<thread %ld> <- '%s'\n",(unsigned long)context->pid_child,buffer);
349 #endif
350
351 /* strtok_r: to be reentrant ! */
352 ptr = buffer;
353 token = strtok_r(buffer," \t\r\n",&ptr);
354 command = identify_token(token);
355
356 switch (command) {
357 case TOK_HELP:
358 send_message_with_args(530,context,"Login with USER and PASS");
359 break;
360 case TOK_USER:
361 if (user_ok) { /* USER command issued 2 times */
362 ret = send_message_with_args(421,context,"USER command issued twice");
363 return 1;
364 }
365 token = strtok_r(NULL,"\r\n",&ptr);
366 if (!token) {
367 ret = send_message_with_args(421,context,"Give me a user name!");
368 return 1;
369 }
370 ret = do_user(token,context);
371 switch (ret) {
372 case E_OK:
373 break;
374 case E_USER_REJECTED: /* user was not accepted */
375 if (!reject_nonexistant)
376 break;
377 ret = send_message_with_args(421,context,"User rejected");
378 return 1;
379 case E_USER_DELETED: /* user exists but was deleted */
380 if (!reject_nonexistant)
381 break;
382 ret = send_message_with_args(421,context,"User deleted");
383 return 1;
384 case E_USER_NUMLOGINS: /* too many logins */
385 ret = send_message_with_args(421,context,"Too many connections with your login");
386 return 1;
387 case E_USER_CLOSED: /* site closed */
388 ret = send_message_with_args(421,context,"Site is closed, try again later");
389 return 1;
390 case E_USER_IDONTEXIST: /* i don't exist, probably a problem with backend */
391 ret = send_message_with_args(501,context,"Mama says I don't exist! (problem with backend?)");
392 return 1;
393 case E_USER_TLSFORCED: /* user must use SSL/TLS */
394 ret = send_message_with_args(421,context,"User MUST connect in TLS/SSL mode");
395 return 1;
396 case E_GROUP_NUMLOGINS: /* too many logins for group */
397 ret = send_message_with_args(421,context,"Too many connections for your group");
398 return 1;
399 default:
400 ret = send_message_with_args(421,context,"User rejected (unknown error)");
401 return 1;
402 }
403 /* validate ip for user */
404 ret = do_user_ip(token,context);
405 if (ret) { /* user was not accepted */
406 ret = send_message_with_args(421,context,"IP not allowed");
407 return 1;
408 }
409 strncpy(username,token,HARD_USERNAME_LENGTH-1);
410 ret = send_message_with_args(331,context,username);
411 user_ok = 1;
412 break;
413 case TOK_PASS:
414 if (!user_ok || pass_ok) {
415 ret = send_message_with_args(421,context,"Incorrect login sequence");
416 return 1;
417 }
418 token = strtok_r(NULL,"\r\n",&ptr);
419 if (!token) {
420 ret = send_message_with_args(421,context,"Give me a password!");
421 return 1;
422 }
423 ret = do_pass(username,token,context);
424 switch (ret) {
425 case E_OK:
426 break;
427 case E_USER_REJECTED: /* user was not accepted */
428 ret = send_message_with_args(421,context,"User rejected");
429 return 1;
430 case E_PASS_REJECTED:
431 ret = send_message_with_args(421,context,"Password rejected");
432 return 1;
433 case E_USER_DELETED: /* user exists but was deleted */
434 ret = send_message_with_args(421,context,"User deleted");
435 return 1;
436 case E_USER_NO_HOME: /* pass is ok, could not chdir */
437 ret = send_message_with_args(421,context,"Could not go to my home directory!");
438 return 1;
439 default:
440 ret = send_message_with_args(421,context,"User rejected (unknown error)");
441 return 1;
442 }
443 /* IF SSL, we should check HERE if the connection has been switched to tls or not */
444 #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
445 if (mainConfig->tls_type == TLS_STRICT_EXPLICIT && !tls_ok) {
446 ret = send_message_with_args(421,context,"TLS session MUST be engaged");
447 return 1;
448 }
449 #endif
450 return 0; /* user + pass ok */
451 break;
452 #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
453 case TOK_AUTH:
454 token = strtok_r(NULL,"\r\n",&ptr);
455 if (!token || token[0]==0) {
456 ret = send_message_with_args(421,context,"Invalid token in AUTH command\n");
457 return 1;
458 }
459 #if defined (HAVE_KRB5)
460 if (strcasecmp(token,"GSSAPI")==0) {
461 ret = do_login_gssapi(context);
462 /** \todo mark the user as already authenticated */
463 break;
464 /* return ret;*/
465 }
466 #endif
467 if (CFG_GET_OPTION(mainConfig,CFG_OPT_DISABLE_TLS)) {
468 ret = send_message_with_args(502,context,"TLS Disabled by config");
469 break;
470 }
471 if (strcasecmp(token,"SSL")==0 || mainConfig->tls_type == TLS_IMPLICIT)
472 context->tls_data_mode = TLS_PRIV; /* SSL must have encrypted data connection */
473 else
474 context->tls_data_mode = TLS_CLEAR;
475 if (mainConfig->tls_type != TLS_IMPLICIT) {
476 ret = send_message_with_args(234, context, token);
477 }
478 ret = tls_auth(token,context);
479 if (ret) { /* couldn't switch to ssl */
480 /* XXX should we send a message ? - with ssl aborted we can't be sure there won't be problems */
481 ret = send_message_with_args(431,context,"Failed TLS negotiation");
482 return 1;
483 }
484 tls_ok = 1;
485 context->connection_flags |= CONNECTION_TLS;
486 break;
487 case TOK_PBSZ:
488 token = strtok_r(NULL,"\r\n",&ptr);
489 /** \todo PBSZ: convert token to int, set the PBSZ size */
490 ret = send_message_with_args(200,context,"Command okay");
491 break;
492 case TOK_PROT:
493 /** \todo PROT: if user is NOT in TLS mode, insult him */
494 token = strtok_r(NULL,"\r\n",&ptr);
495 if (strcasecmp("P",token)==0)
496 context->tls_data_mode = TLS_PRIV;
497 else if (strcasecmp("C",token)==0)
498 context->tls_data_mode = TLS_CLEAR;
499 else {
500 ret = send_message_with_args(550,context,"PROT","must be C or P");
501 break;
502 }
503 ret = send_message_with_args(200,context,"PROT command okay");
504 break;
505 #else /* HAVE_OPENSSL */
506 case TOK_AUTH:
507 case TOK_PBSZ:
508 case TOK_PROT:
509 ret = send_message_with_args(530,context,"TLS commands disabled");
510 break;
511 #endif
512 case TOK_FEAT:
513 {
514 wzd_string_t * str = STR("feat");
515 ret = do_print_message(str,NULL,context);
516 str_deallocate(str);
517 }
518 break;
519 case TOK_OPTS:
520 {
521 wzd_string_t *s1, *s2;
522 token = strtok_r(NULL,"\r\n",&ptr);
523 s1 = STR("opts");
524 s2 = STR(token);
525 ret = do_opts(s1,s2,context);
526 str_deallocate(s1);
527 str_deallocate(s2);
528 }
529 break;
530 case TOK_IDNT:
531 {
532 char * ident, * address;
533 char ip[INET6_ADDRSTRLEN];
534
535 if (context->idnt_address != NULL) {
536 out_log(LEVEL_INFO,"WARNING mutiple IDNT commands\n");
537 ret = send_message_with_args(530,context,"Multiple IDNT commands");
538 return 1;
539 }
540
541 #if defined(IPV6_SUPPORT)
542 if (context->family == WZD_INET6) {
543 inet_ntop(AF_INET6,context->hostip,ip,INET6_ADDRSTRLEN);
544 } else
545 #endif
546 {
547 inet_ntop(AF_INET,context->hostip,ip,INET_ADDRSTRLEN);
548 }
549
550 if (ip_is_bnc(ip, mainConfig)!=1) {
551 out_log(LEVEL_INFO,"WARNING IDNT command received from a non-BNC (%s)\n",ip);
552 ret = send_message_with_args(530,context,"Permission denied");
553 return 1;
554 }
555
556 ident = strtok_r(NULL,"@",&ptr);
557 address = strtok_r(NULL,":",&ptr);
558
559 if (!ident || !address || (ptr && strlen(ptr)==0) ) {
560 ret = send_message_with_args(501,context,"Syntax error");
561 return 1;
562 }
563
564 /* XXX optional: check if hostname is valid */
565 ret = iptohostname(address,WZD_INET_NONE,NULL,NULL);
566 if (ret != 0) {
567 out_log(LEVEL_NORMAL,"WARNING Invalid hostname passed to IDNT (received %s)\n",address);
568 ret = send_message_with_args(501,context,"IDNT failed");
569 return 1;
570 }
571
572 context->ident = strdup(ident);
573 context->idnt_address = strdup(address);
574
575 /* bnc doesn't expect any reply */
576 }
577 break;
578 default:
579 out_log(LEVEL_INFO,"Invalid login sequence: '%s'\n",buffer);
580 ret = send_message_with_args(530,context,"Invalid login sequence");
581 return 1;
582 } /* switch (command) */
583
584 } /* while (1) */
585
586 return ret;
587 }
588
589 #if defined (HAVE_KRB5)
do_login_gssapi(wzd_context_t * context)590 static int do_login_gssapi(wzd_context_t * context)
591 {
592 char buffer[BUFFER_LEN];
593 char * ptr;
594 char * token;
595 char * base64data;
596 int command;
597 int ret;
598
599 /** \todo initialize GSSAPI only once */
600 ret = auth_gssapi_init(&context->gssapi_data);
601 if (ret) {
602 ret = send_message_with_args(550,context,"GSSAPI","Initialisation failed");
603 return 1;
604 }
605
606 ret = send_message_with_args(334, context, "Waiting for ", "ADAT");
607
608 while (1) {
609 /* wait response */
610 ret = (context->read_fct)(context->controlfd,buffer,BUFFER_LEN,0,HARD_XFER_TIMEOUT,context);
611
612 if (ret == 0) {
613 out_err(LEVEL_FLOOD,"Connection closed or timeout (socket %d)\n",context->controlfd);
614 return 1;
615 }
616 if (ret==-1) {
617 out_err(LEVEL_FLOOD,"Error reading client response (socket %d)\n",context->controlfd);
618 return 1;
619 }
620
621 /* this replace the memset (bzero ?) some lines before */
622 buffer[ret] = '\0';
623
624 if (buffer[0]=='\0') continue;
625
626 {
627 size_t length = strlen(buffer);
628 while (length > 0 && (buffer[length-1]=='\r' || buffer[length-1]=='\n'))
629 buffer[length-- -1] = '\0';
630 set_action(context,buffer);
631 }
632
633 #ifdef DEBUG
634 out_err(LEVEL_FLOOD,"<thread %ld> <- '%s'\n",(unsigned long)context->pid_child,buffer);
635 #endif
636
637 /* strtok_r: to be reentrant ! */
638 ptr = buffer;
639 token = strtok_r(buffer," \t\r\n",&ptr);
640 command = identify_token(token);
641
642 switch (command) {
643 case TOK_HELP:
644 send_message_with_args(530,context,"Login with USER and PASS");
645 break;
646 case TOK_ADAT:
647 {
648 char * ptr_out = NULL;
649 size_t length_out;
650
651 base64data = strtok_r(NULL," \t\r\n",&ptr);
652 out_log(LEVEL_FLOOD,"DEBUG: received ADAT [%s]\n",base64data);
653 ret = auth_gssapi_accept_sec_context(context->gssapi_data, base64data, strlen(base64data), &ptr_out, &length_out);
654 switch (ret) {
655 case 1:
656 ret = send_message_with_args(334, context, "ADAT=", ptr_out);
657 break;
658 case 0:
659 ret = send_message_with_args(235,context,"ADAT=", ptr_out);
660 /* authenticated, now switch read and write functions */
661 context->read_fct = auth_gssapi_read;
662 context->write_fct = auth_gssapi_write;
663 return 0;
664 break;
665 default:
666 ret = send_message_with_args(535,context,"GSSAPI authentication failed");
667 return 1;
668 }
669 #if 0
670 length_in = base64_encode((u_int8_t*)ptr_out,length_out,(u_int8_t*)buffer2);
671 ret = send_message_with_args(334, context, "ADAT=", buffer2);
672 send_message_with_args(530,context,"I don't know yet how to play with ADAT");
673 #endif
674 }
675 break;
676 default:
677 out_log(LEVEL_INFO,"Invalid login sequence: '%s'\n",buffer);
678 ret = send_message_with_args(530,context,"Invalid login sequence");
679 return 1;
680 } /* switch (command) */
681
682 } /* while (1) */
683
684 return 1; /* error */
685 }
686
do_mic(wzd_string_t * name,wzd_string_t * param,wzd_context_t * context)687 int do_mic(wzd_string_t *name, wzd_string_t *param, wzd_context_t * context)
688 {
689 out_err(LEVEL_FLOOD,"DEBUG: received MIC [%s]\n",str_tochar(param));
690
691 return 0;
692 }
693 #else /* HAVE_KRB5 */
do_mic(wzd_string_t * name,wzd_string_t * param,wzd_context_t * context)694 int do_mic(wzd_string_t *name, wzd_string_t *param, wzd_context_t * context)
695 {
696 int ret;
697
698 ret = send_message_with_args(501,context,"Command not supported");
699
700 return 0;
701 }
702 #endif /* HAVE_KRB5 */
703
704 /*************** login sequence **********************/
705 /** \brief Execute login loop
706 *
707 * \return 0 if login is ok
708 */
do_login(wzd_context_t * context)709 int do_login(wzd_context_t * context)
710 {
711 int ret;
712
713 /* welcome msg */
714 ret = send_message(220,context);
715
716 /* mini server loop, login */
717 ret = do_login_loop(context);
718
719 {
720 const char * groupname = NULL;
721 const char * remote_host;
722 struct hostent *h;
723 char inet_str[256];
724 int af = (context->family == WZD_INET6) ? AF_INET6 : AF_INET;
725 wzd_user_t * user;
726
727 user = GetUserByID(context->userid);
728 if (user && user->group_num > 0) groupname = GetGroupByID(user->groups[0])->groupname;
729 inet_str[0] = '\0';
730 inet_ntop(af,context->hostip,inet_str,sizeof(inet_str));
731 h = gethostbyaddr((char*)&context->hostip,sizeof(context->hostip),af);
732 if (h==NULL)
733 remote_host = inet_str;
734 else
735 remote_host = h->h_name;
736 out_log(LEVEL_INFO,"%s from %s\n",(ret)?"LOGIN FAILURE":"LOGIN OKAY",remote_host);
737 log_message( (ret)?"LOGIN_FAILED":"LOGIN" ,"%s (%s) \"%s\" \"%s\" \"%s\"",
738 (remote_host)?remote_host:"no host!",
739 inet_str,
740 user ? user->username : "unknown",
741 (groupname)?groupname:"No Group",
742 user ? user->tagline : "unknown"
743 );
744 }
745
746 return ret;
747 }
748
749
750
751
752
753
754
755 /*************** check_tls_forced ********************/
756 /** check if tls connection must be enforced for user
757 * return E_OK if user is in tls mode or is not forced to user
758 * E_USER_TLSFORCED if user should be in tls but is not
759 */
check_tls_forced(wzd_context_t * context)760 static int check_tls_forced(wzd_context_t * context)
761 {
762 wzd_user_t * user;
763 /* wzd_group_t *group;
764 int i;*/
765
766 user = GetUserByID(context->userid);
767
768 if (user->flags && strchr(user->flags,FLAG_TLS)) {
769 if ( !(context->connection_flags & CONNECTION_TLS) ) {
770 return E_USER_TLSFORCED;
771 }
772 }
773 /* TODO XXX FIXME implement flags for groups */
774 #if 0
775 /* try groups */
776 for (i=0; i<user->group_num; i++) {
777 group = GetGroupByID(user->groups[i]);
778 if (group->flags && strchr(group->flags,FLAG_TLS)) {
779 if ( !(context->connection_flags & CONNECTION_TLS) ) {
780 return 1;
781 }
782 }
783 #endif
784
785 return E_OK;
786 }
787
788