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