r23779: Change from v2 or later to v3 or later.
[ira/wip.git] / source3 / smbd / password.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /* users from session setup */
24 static char *session_userlist = NULL;
25 static int len_session_userlist = 0;
26 /* workgroup from session setup. */
27 static char *session_workgroup = NULL;
28
29 /* this holds info on user ids that are already validated for this VC */
30 static user_struct *validated_users;
31 static int next_vuid = VUID_OFFSET;
32 static int num_validated_vuids;
33
34 /****************************************************************************
35  Check if a uid has been validated, and return an pointer to the user_struct
36  if it has. NULL if not. vuid is biased by an offset. This allows us to
37  tell random client vuid's (normally zero) from valid vuids.
38 ****************************************************************************/
39
40 user_struct *get_valid_user_struct(uint16 vuid)
41 {
42         user_struct *usp;
43         int count=0;
44
45         if (vuid == UID_FIELD_INVALID)
46                 return NULL;
47
48         for (usp=validated_users;usp;usp=usp->next,count++) {
49                 if (vuid == usp->vuid && usp->server_info) {
50                         if (count > 10) {
51                                 DLIST_PROMOTE(validated_users, usp);
52                         }
53                         return usp;
54                 }
55         }
56
57         return NULL;
58 }
59
60 /****************************************************************************
61  Get the user struct of a partial NTLMSSP login
62 ****************************************************************************/
63
64 user_struct *get_partial_auth_user_struct(uint16 vuid)
65 {
66         user_struct *usp;
67         int count=0;
68
69         if (vuid == UID_FIELD_INVALID)
70                 return NULL;
71
72         for (usp=validated_users;usp;usp=usp->next,count++) {
73                 if (vuid == usp->vuid && !usp->server_info) {
74                         if (count > 10) {
75                                 DLIST_PROMOTE(validated_users, usp);
76                         }
77                         return usp;
78                 }
79         }
80
81         return NULL;
82 }
83
84 /****************************************************************************
85  Invalidate a uid.
86 ****************************************************************************/
87
88 void invalidate_vuid(uint16 vuid)
89 {
90         user_struct *vuser = get_valid_user_struct(vuid);
91
92         if (vuser == NULL)
93                 return;
94         
95         session_yield(vuser);
96
97         data_blob_free(&vuser->session_key);
98
99         DLIST_REMOVE(validated_users, vuser);
100
101         /* clear the vuid from the 'cache' on each connection, and
102            from the vuid 'owner' of connections */
103         conn_clear_vuid_cache(vuid);
104
105         TALLOC_FREE(vuser);
106         num_validated_vuids--;
107 }
108
109 /****************************************************************************
110  Invalidate all vuid entries for this process.
111 ****************************************************************************/
112
113 void invalidate_all_vuids(void)
114 {
115         user_struct *usp, *next=NULL;
116
117         for (usp=validated_users;usp;usp=next) {
118                 next = usp->next;
119                 
120                 invalidate_vuid(usp->vuid);
121         }
122 }
123
124 /**
125  *  register that a valid login has been performed, establish 'session'.
126  *  @param server_info The token returned from the authentication process. 
127  *   (now 'owned' by register_vuid)
128  *
129  *  @param session_key The User session key for the login session (now also
130  *  'owned' by register_vuid)
131  *
132  *  @param respose_blob The NT challenge-response, if available.  (May be
133  *  freed after this call)
134  *
135  *  @param smb_name The untranslated name of the user
136  *
137  *  @return Newly allocated vuid, biased by an offset. (This allows us to
138  *   tell random client vuid's (normally zero) from valid vuids.)
139  *
140  */
141
142 int register_vuid(auth_serversupplied_info *server_info,
143                   DATA_BLOB session_key, DATA_BLOB response_blob,
144                   const char *smb_name)
145 {
146         user_struct *vuser;
147
148         /* Paranoia check. */
149         if(lp_security() == SEC_SHARE) {
150                 smb_panic("Tried to register uid in security=share");
151         }
152
153         /* Limit allowed vuids to 16bits - VUID_OFFSET. */
154         if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) {
155                 data_blob_free(&session_key);
156                 return UID_FIELD_INVALID;
157         }
158
159         if((vuser = TALLOC_ZERO_P(NULL, user_struct)) == NULL) {
160                 DEBUG(0,("Failed to talloc users struct!\n"));
161                 data_blob_free(&session_key);
162                 return UID_FIELD_INVALID;
163         }
164
165         /* Allocate a free vuid. Yes this is a linear search... :-) */
166         while( get_valid_user_struct(next_vuid) != NULL ) {
167                 next_vuid++;
168                 /* Check for vuid wrap. */
169                 if (next_vuid == UID_FIELD_INVALID)
170                         next_vuid = VUID_OFFSET;
171         }
172
173         DEBUG(10,("register_vuid: allocated vuid = %u\n",
174                   (unsigned int)next_vuid ));
175
176         vuser->vuid = next_vuid;
177
178         if (!server_info) {
179                 /*
180                  * This happens in an unfinished NTLMSSP session setup. We
181                  * need to allocate a vuid between the first and second calls
182                  * to NTLMSSP.
183                  */
184                 next_vuid++;
185                 num_validated_vuids++;
186                 
187                 vuser->server_info = NULL;
188                 
189                 DLIST_ADD(validated_users, vuser);
190                 
191                 return vuser->vuid;
192         }
193
194         /* use this to keep tabs on all our info from the authentication */
195         vuser->server_info = server_info;
196         /* Ensure that the server_info will dissapear with the vuser it is now attached to */
197         talloc_steal(vuser, vuser->server_info);
198
199         /* the next functions should be done by a SID mapping system (SMS) as
200          * the new real sam db won't have reference to unix uids or gids
201          */
202         
203         vuser->uid = server_info->uid;
204         vuser->gid = server_info->gid;
205         
206         vuser->n_groups = server_info->n_groups;
207         if (vuser->n_groups) {
208                 if (!(vuser->groups = (gid_t *)talloc_memdup(vuser, server_info->groups,
209                                                              sizeof(gid_t) *
210                                                              vuser->n_groups))) {
211                         DEBUG(0,("register_vuid: failed to talloc_memdup "
212                                  "vuser->groups\n"));
213                         data_blob_free(&session_key);
214                         TALLOC_FREE(vuser);
215                         return UID_FIELD_INVALID;
216                 }
217         }
218
219         vuser->guest = server_info->guest;
220         fstrcpy(vuser->user.unix_name, server_info->unix_name); 
221
222         /* This is a potentially untrusted username */
223         alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$",
224                      sizeof(vuser->user.smb_name));
225
226         fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account));
227         fstrcpy(vuser->user.full_name,
228                 pdb_get_fullname(server_info->sam_account));
229
230         {
231                 /* Keep the homedir handy */
232                 const char *homedir =
233                         pdb_get_homedir(server_info->sam_account);
234                 const char *logon_script =
235                         pdb_get_logon_script(server_info->sam_account);
236
237                 if (!IS_SAM_DEFAULT(server_info->sam_account,
238                                     PDB_UNIXHOMEDIR)) {
239                         const char *unix_homedir =
240                                 pdb_get_unix_homedir(server_info->sam_account);
241                         if (unix_homedir) {
242                                 vuser->unix_homedir = unix_homedir;
243                         }
244                 } else {
245                         struct passwd *passwd =
246                                 getpwnam_alloc(vuser, vuser->user.unix_name);
247                         if (passwd) {
248                                 vuser->unix_homedir = passwd->pw_dir;
249                                 /* Ensure that the unix_homedir now
250                                  * belongs to vuser, so it goes away
251                                  * with it, not with passwd below: */
252                                 talloc_steal(vuser, vuser->unix_homedir);
253                                 TALLOC_FREE(passwd);
254                         }
255                 }
256                 
257                 if (homedir) {
258                         vuser->homedir = homedir;
259                 }
260                 if (logon_script) {
261                         vuser->logon_script = logon_script;
262                 }
263         }
264
265         vuser->session_key = session_key;
266
267         DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", 
268                   (unsigned int)vuser->uid, 
269                   (unsigned int)vuser->gid,
270                   vuser->user.unix_name, vuser->user.smb_name,
271                   vuser->user.domain, vuser->guest ));
272
273         DEBUG(3, ("User name: %s\tReal name: %s\n", vuser->user.unix_name,
274                   vuser->user.full_name));      
275
276         if (server_info->ptok) {
277                 vuser->nt_user_token = dup_nt_token(vuser, server_info->ptok);
278         } else {
279                 DEBUG(1, ("server_info does not contain a user_token - "
280                           "cannot continue\n"));
281                 TALLOC_FREE(vuser);
282                 data_blob_free(&session_key);
283                 return UID_FIELD_INVALID;
284         }
285
286         DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",
287                  (int)vuser->uid,vuser->user.unix_name, vuser->vuid));
288
289         next_vuid++;
290         num_validated_vuids++;
291
292         DLIST_ADD(validated_users, vuser);
293
294         if (!session_claim(vuser)) {
295                 DEBUG(1, ("Failed to claim session for vuid=%d\n",
296                           vuser->vuid));
297                 invalidate_vuid(vuser->vuid);
298                 return UID_FIELD_INVALID;
299         }
300
301         /* Register a home dir service for this user iff
302         
303            (a) This is not a guest connection,
304            (b) we have a home directory defined 
305            (c) there s not an existing static share by that name
306            
307            If a share exists by this name (autoloaded or not) reuse it . */
308
309         vuser->homes_snum = -1;
310
311         if ( (!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) 
312         {
313                 int servicenumber = lp_servicenumber(vuser->user.unix_name);
314
315                 if ( servicenumber == -1 ) {
316                         DEBUG(3, ("Adding homes service for user '%s' using "
317                                   "home directory: '%s'\n", 
318                                 vuser->user.unix_name, vuser->unix_homedir));
319                         vuser->homes_snum =
320                                 add_home_service(vuser->user.unix_name, 
321                                                  vuser->user.unix_name,
322                                                  vuser->unix_homedir);
323                 } else {
324                         DEBUG(3, ("Using static (or previously created) "
325                                   "service for user '%s'; path = '%s'\n", 
326                                   vuser->user.unix_name,
327                                   lp_pathname(servicenumber) ));
328                         vuser->homes_snum = servicenumber;
329                 }
330         } 
331         
332         if (srv_is_signing_negotiated() && !vuser->guest &&
333             !srv_signing_started()) {
334                 /* Try and turn on server signing on the first non-guest
335                  * sessionsetup. */
336                 srv_set_signing(vuser->session_key, response_blob);
337         }
338         
339         /* fill in the current_user_info struct */
340         set_current_user_info( &vuser->user );
341
342
343         return vuser->vuid;
344 }
345
346 /****************************************************************************
347  Add a name to the session users list.
348 ****************************************************************************/
349
350 void add_session_user(const char *user)
351 {
352         fstring suser;
353         struct passwd *passwd;
354
355         if (!(passwd = Get_Pwnam(user)))
356                 return;
357
358         fstrcpy(suser,passwd->pw_name);
359
360         if(!*suser)
361                 return;
362
363         if( session_userlist && in_list(suser,session_userlist,False) )
364                 return;
365
366         if( !session_userlist ||
367             (strlen(suser) + strlen(session_userlist) + 2 >=
368              len_session_userlist) ) {
369                 char *newlist;
370
371                 if (len_session_userlist > 128 * PSTRING_LEN) {
372                         DEBUG(3,("add_session_user: session userlist already "
373                                  "too large.\n"));
374                         return;
375                 }
376                 newlist = (char *)SMB_REALLOC_KEEP_OLD_ON_ERROR(
377                         session_userlist,
378                         len_session_userlist + PSTRING_LEN );
379                 if( newlist == NULL ) {
380                         DEBUG(1,("Unable to resize session_userlist\n"));
381                         return;
382                 }
383                 if (!session_userlist) {
384                         *newlist = '\0';
385                 }
386                 session_userlist = newlist;
387                 len_session_userlist += PSTRING_LEN;
388         }
389
390         safe_strcat(session_userlist," ",len_session_userlist-1);
391         safe_strcat(session_userlist,suser,len_session_userlist-1);
392 }
393
394 /****************************************************************************
395  In security=share mode we need to store the client workgroup, as that's
396   what Vista uses for the NTLMv2 calculation.
397 ****************************************************************************/
398
399 void add_session_workgroup(const char *workgroup)
400 {
401         if (session_workgroup) {
402                 SAFE_FREE(session_workgroup);
403         }
404         session_workgroup = smb_xstrdup(workgroup);
405 }
406
407 /****************************************************************************
408  In security=share mode we need to return the client workgroup, as that's
409   what Vista uses for the NTLMv2 calculation.
410 ****************************************************************************/
411
412 const char *get_session_workgroup(void)
413 {
414         return session_workgroup;
415 }
416
417 /****************************************************************************
418  Check if a user is in a netgroup user list. If at first we don't succeed,
419  try lower case.
420 ****************************************************************************/
421
422 BOOL user_in_netgroup(const char *user, const char *ngname)
423 {
424 #ifdef HAVE_NETGROUP
425         static char *mydomain = NULL;
426         fstring lowercase_user;
427
428         if (mydomain == NULL)
429                 yp_get_default_domain(&mydomain);
430
431         if(mydomain == NULL) {
432                 DEBUG(5,("Unable to get default yp domain, let's try without specifying it\n"));
433         }
434
435         DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
436                 user, mydomain?mydomain:"(ANY)", ngname));
437
438         if (innetgr(ngname, NULL, user, mydomain)) {
439                 DEBUG(5,("user_in_netgroup: Found\n"));
440                 return (True);
441         } else {
442
443                 /*
444                  * Ok, innetgr is case sensitive. Try once more with lowercase
445                  * just in case. Attempt to fix #703. JRA.
446                  */
447
448                 fstrcpy(lowercase_user, user);
449                 strlower_m(lowercase_user);
450         
451                 DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
452                         lowercase_user, mydomain?mydomain:"(ANY)", ngname));
453
454                 if (innetgr(ngname, NULL, lowercase_user, mydomain)) {
455                         DEBUG(5,("user_in_netgroup: Found\n"));
456                         return (True);
457                 }
458         }
459 #endif /* HAVE_NETGROUP */
460         return False;
461 }
462
463 /****************************************************************************
464  Check if a user is in a user list - can check combinations of UNIX
465  and netgroup lists.
466 ****************************************************************************/
467
468 BOOL user_in_list(const char *user,const char **list)
469 {
470         if (!list || !*list)
471                 return False;
472
473         DEBUG(10,("user_in_list: checking user %s in list\n", user));
474
475         while (*list) {
476
477                 DEBUG(10,("user_in_list: checking user |%s| against |%s|\n",
478                           user, *list));
479
480                 /*
481                  * Check raw username.
482                  */
483                 if (strequal(user, *list))
484                         return(True);
485
486                 /*
487                  * Now check to see if any combination
488                  * of UNIX and netgroups has been specified.
489                  */
490
491                 if(**list == '@') {
492                         /*
493                          * Old behaviour. Check netgroup list
494                          * followed by UNIX list.
495                          */
496                         if(user_in_netgroup(user, *list +1))
497                                 return True;
498                         if(user_in_group(user, *list +1))
499                                 return True;
500                 } else if (**list == '+') {
501
502                         if((*(*list +1)) == '&') {
503                                 /*
504                                  * Search UNIX list followed by netgroup.
505                                  */
506                                 if(user_in_group(user, *list +2))
507                                         return True;
508                                 if(user_in_netgroup(user, *list +2))
509                                         return True;
510
511                         } else {
512
513                                 /*
514                                  * Just search UNIX list.
515                                  */
516
517                                 if(user_in_group(user, *list +1))
518                                         return True;
519                         }
520
521                 } else if (**list == '&') {
522
523                         if(*(*list +1) == '+') {
524                                 /*
525                                  * Search netgroup list followed by UNIX list.
526                                  */
527                                 if(user_in_netgroup(user, *list +2))
528                                         return True;
529                                 if(user_in_group(user, *list +2))
530                                         return True;
531                         } else {
532                                 /*
533                                  * Just search netgroup list.
534                                  */
535                                 if(user_in_netgroup(user, *list +1))
536                                         return True;
537                         }
538                 }
539     
540                 list++;
541         }
542         return(False);
543 }
544
545 /****************************************************************************
546  Check if a username is valid.
547 ****************************************************************************/
548
549 static BOOL user_ok(const char *user, int snum)
550 {
551         char **valid, **invalid;
552         BOOL ret;
553
554         valid = invalid = NULL;
555         ret = True;
556
557         if (lp_invalid_users(snum)) {
558                 str_list_copy(&invalid, lp_invalid_users(snum));
559                 if (invalid &&
560                     str_list_substitute(invalid, "%S", lp_servicename(snum))) {
561
562                         /* This is used in sec=share only, so no current user
563                          * around to pass to str_list_sub_basic() */
564
565                         if ( invalid && str_list_sub_basic(invalid, "", "") ) {
566                                 ret = !user_in_list(user,
567                                                     (const char **)invalid);
568                         }
569                 }
570         }
571         if (invalid)
572                 str_list_free (&invalid);
573
574         if (ret && lp_valid_users(snum)) {
575                 str_list_copy(&valid, lp_valid_users(snum));
576                 if ( valid &&
577                      str_list_substitute(valid, "%S", lp_servicename(snum)) ) {
578
579                         /* This is used in sec=share only, so no current user
580                          * around to pass to str_list_sub_basic() */
581
582                         if ( valid && str_list_sub_basic(valid, "", "") ) {
583                                 ret = user_in_list(user, (const char **)valid);
584                         }
585                 }
586         }
587         if (valid)
588                 str_list_free (&valid);
589
590         if (ret && lp_onlyuser(snum)) {
591                 char **user_list = str_list_make (lp_username(snum), NULL);
592                 if (user_list &&
593                     str_list_substitute(user_list, "%S",
594                                         lp_servicename(snum))) {
595                         ret = user_in_list(user, (const char **)user_list);
596                 }
597                 if (user_list) str_list_free (&user_list);
598         }
599
600         return(ret);
601 }
602
603 /****************************************************************************
604  Validate a group username entry. Return the username or NULL.
605 ****************************************************************************/
606
607 static char *validate_group(char *group, DATA_BLOB password,int snum)
608 {
609 #ifdef HAVE_NETGROUP
610         {
611                 char *host, *user, *domain;
612                 setnetgrent(group);
613                 while (getnetgrent(&host, &user, &domain)) {
614                         if (user) {
615                                 if (user_ok(user, snum) && 
616                                     password_ok(user,password)) {
617                                         endnetgrent();
618                                         return(user);
619                                 }
620                         }
621                 }
622                 endnetgrent();
623         }
624 #endif
625   
626 #ifdef HAVE_GETGRENT
627         {
628                 struct group *gptr;
629                 setgrent();
630                 while ((gptr = (struct group *)getgrent())) {
631                         if (strequal(gptr->gr_name,group))
632                                 break;
633                 }
634
635                 /*
636                  * As user_ok can recurse doing a getgrent(), we must
637                  * copy the member list into a pstring on the stack before
638                  * use. Bug pointed out by leon@eatworms.swmed.edu.
639                  */
640
641                 if (gptr) {
642                         pstring member_list;
643                         char *member;
644                         size_t copied_len = 0;
645                         int i;
646
647                         *member_list = '\0';
648                         member = member_list;
649
650                         for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) {
651                                 size_t member_len = strlen(gptr->gr_mem[i])+1;
652                                 if(copied_len+member_len < sizeof(pstring)) { 
653
654                                         DEBUG(10,("validate_group: = gr_mem = "
655                                                   "%s\n", gptr->gr_mem[i]));
656
657                                         safe_strcpy(member, gptr->gr_mem[i],
658                                                     sizeof(pstring) -
659                                                     copied_len - 1);
660                                         copied_len += member_len;
661                                         member += copied_len;
662                                 } else {
663                                         *member = '\0';
664                                 }
665                         }
666
667                         endgrent();
668
669                         member = member_list;
670                         while (*member) {
671                                 static fstring name;
672                                 fstrcpy(name,member);
673                                 if (user_ok(name,snum) &&
674                                     password_ok(name,password)) {
675                                         endgrent();
676                                         return(&name[0]);
677                                 }
678
679                                 DEBUG(10,("validate_group = member = %s\n",
680                                           member));
681
682                                 member += strlen(member) + 1;
683                         }
684                 } else {
685                         endgrent();
686                         return NULL;
687                 }
688         }
689 #endif
690         return(NULL);
691 }
692
693 /****************************************************************************
694  Check for authority to login to a service with a given username/password.
695  Note this is *NOT* used when logging on using sessionsetup_and_X.
696 ****************************************************************************/
697
698 BOOL authorise_login(int snum, fstring user, DATA_BLOB password, 
699                      BOOL *guest)
700 {
701         BOOL ok = False;
702         
703 #ifdef DEBUG_PASSWORD
704         DEBUG(100,("authorise_login: checking authorisation on "
705                    "user=%s pass=%s\n", user,password.data));
706 #endif
707
708         *guest = False;
709   
710         /* there are several possibilities:
711                 1) login as the given user with given password
712                 2) login as a previously registered username with the given 
713                    password
714                 3) login as a session list username with the given password
715                 4) login as a previously validated user/password pair
716                 5) login as the "user =" user with given password
717                 6) login as the "user =" user with no password 
718                    (guest connection)
719                 7) login as guest user with no password
720
721                 if the service is guest_only then steps 1 to 5 are skipped
722         */
723
724         /* now check the list of session users */
725         if (!ok) {
726                 char *auser;
727                 char *user_list = NULL;
728
729                 if ( session_userlist )
730                         user_list = SMB_STRDUP(session_userlist);
731                 else
732                         user_list = SMB_STRDUP("");
733
734                 if (!user_list)
735                         return(False);
736                 
737                 for (auser=strtok(user_list,LIST_SEP); !ok && auser;
738                      auser = strtok(NULL,LIST_SEP)) {
739                         fstring user2;
740                         fstrcpy(user2,auser);
741                         if (!user_ok(user2,snum))
742                                 continue;
743                         
744                         if (password_ok(user2,password)) {
745                                 ok = True;
746                                 fstrcpy(user,user2);
747                                 DEBUG(3,("authorise_login: ACCEPTED: session "
748                                          "list username (%s) and given "
749                                          "password ok\n", user));
750                         }
751                 }
752
753                 SAFE_FREE(user_list);
754         }
755         
756         /* check the user= fields and the given password */
757         if (!ok && lp_username(snum)) {
758                 char *auser;
759                 pstring user_list;
760                 pstrcpy(user_list,lp_username(snum));
761                 
762                 pstring_sub(user_list,"%S",lp_servicename(snum));
763                 
764                 for (auser=strtok(user_list,LIST_SEP); auser && !ok;
765                      auser = strtok(NULL,LIST_SEP)) {
766                         if (*auser == '@') {
767                                 auser = validate_group(auser+1,password,snum);
768                                 if (auser) {
769                                         ok = True;
770                                         fstrcpy(user,auser);
771                                         DEBUG(3,("authorise_login: ACCEPTED: "
772                                                  "group username and given "
773                                                  "password ok (%s)\n", user));
774                                 }
775                         } else {
776                                 fstring user2;
777                                 fstrcpy(user2,auser);
778                                 if (user_ok(user2,snum) &&
779                                     password_ok(user2,password)) {
780                                         ok = True;
781                                         fstrcpy(user,user2);
782                                         DEBUG(3,("authorise_login: ACCEPTED: "
783                                                  "user list username and "
784                                                  "given password ok (%s)\n",
785                                                  user));
786                                 }
787                         }
788                 }
789         }
790
791         /* check for a normal guest connection */
792         if (!ok && GUEST_OK(snum)) {
793                 fstring guestname;
794                 fstrcpy(guestname,lp_guestaccount());
795                 if (Get_Pwnam(guestname)) {
796                         fstrcpy(user,guestname);
797                         ok = True;
798                         DEBUG(3,("authorise_login: ACCEPTED: guest account "
799                                  "and guest ok (%s)\n", user));
800                 } else {
801                         DEBUG(0,("authorise_login: Invalid guest account "
802                                  "%s??\n",guestname));
803                 }
804                 *guest = True;
805         }
806
807         if (ok && !user_ok(user, snum)) {
808                 DEBUG(0,("authorise_login: rejected invalid user %s\n",user));
809                 ok = False;
810         }
811
812         return(ok);
813 }