Now we're doing the substituion in the lp_string code remove the erroneous
[sharpe/samba-autobuild/.git] / source3 / smbd / service.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    service (connection) opening and closing
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25
26 extern struct timeval smb_last_time;
27 extern int case_default;
28 extern BOOL case_preserve;
29 extern BOOL short_case_preserve;
30 extern BOOL case_mangle;
31 extern BOOL case_sensitive;
32 extern BOOL use_mangled_map;
33 extern fstring remote_machine;
34 extern userdom_struct current_user_info;
35 extern fstring remote_machine;
36
37
38 /****************************************************************************
39 load parameters specific to a connection/service
40 ****************************************************************************/
41 BOOL become_service(connection_struct *conn,BOOL do_chdir)
42 {
43         extern char magic_char;
44         static connection_struct *last_conn;
45         int snum;
46
47         if (!conn)  {
48                 last_conn = NULL;
49                 return(False);
50         }
51
52         conn->lastused = smb_last_time.tv_sec;
53
54         snum = SNUM(conn);
55   
56         if (do_chdir &&
57             vfs_ChDir(conn,conn->connectpath) != 0 &&
58             vfs_ChDir(conn,conn->origpath) != 0) {
59                 DEBUG(0,("chdir (%s) failed\n",
60                          conn->connectpath));
61                 return(False);
62         }
63
64         if (conn == last_conn)
65                 return(True);
66
67         last_conn = conn;
68
69         case_default = lp_defaultcase(snum);
70         case_preserve = lp_preservecase(snum);
71         short_case_preserve = lp_shortpreservecase(snum);
72         case_mangle = lp_casemangle(snum);
73         case_sensitive = lp_casesensitive(snum);
74         magic_char = lp_magicchar(snum);
75         use_mangled_map = (*lp_mangled_map(snum) ? True:False);
76         return(True);
77 }
78
79 /****************************************************************************
80  Add a home service. Returns the new service number or -1 if fail.
81 ****************************************************************************/
82
83 int add_home_service(char *service, char *homedir)
84 {
85         int iHomeService;
86         int iService;
87         fstring new_service;
88         char *usr_p = NULL;
89
90         if (!service || !homedir)
91                 return -1;
92
93         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
94                 return -1;
95
96         /*
97          * If this is a winbindd provided username, remove
98          * the domain component before adding the service.
99          * Log a warning if the "path=" parameter does not
100          * include any macros.
101          */
102
103         fstrcpy(new_service, service);
104
105         if ((usr_p = strchr(service,*lp_winbind_separator())) != NULL)
106                 fstrcpy(new_service, usr_p+1);
107
108         lp_add_home(new_service,iHomeService,homedir);
109         iService = lp_servicenumber(new_service);
110
111         return iService;
112 }
113
114 /****************************************************************************
115  Find a service entry. service is always in dos codepage.
116 ****************************************************************************/
117
118 int find_service(char *service)
119 {
120    int iService;
121
122    all_string_sub(service,"\\","/",0);
123
124    iService = lp_servicenumber(service);
125
126    /* now handle the special case of a home directory */
127    if (iService < 0)
128    {
129       char *phome_dir = get_user_home_dir(service);
130
131       if(!phome_dir)
132       {
133         /*
134          * Try mapping the servicename, it may
135          * be a Windows to unix mapped user name.
136          */
137         if(map_username(service))
138           phome_dir = get_user_home_dir(service);
139       }
140
141       DEBUG(3,("checking for home directory %s gave %s\n",service,
142             phome_dir?phome_dir:"(NULL)"));
143
144       iService = add_home_service(service,phome_dir);
145    }
146
147    /* If we still don't have a service, attempt to add it as a printer. */
148    if (iService < 0)
149    {
150       int iPrinterService;
151
152       if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
153       {
154          char *pszTemp;
155
156          DEBUG(3,("checking whether %s is a valid printer name...\n", service));
157          pszTemp = PRINTCAP;
158          if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
159          {
160             DEBUG(3,("%s is a valid printer name\n", service));
161             DEBUG(3,("adding %s as a printer service\n", service));
162             lp_add_printer(service,iPrinterService);
163             iService = lp_servicenumber(service);
164             if (iService < 0)
165                DEBUG(0,("failed to add %s as a printer service!\n", service));
166          }
167          else
168             DEBUG(3,("%s is not a valid printer name\n", service));
169       }
170    }
171
172    /* Check for default vfs service?  Unsure whether to implement this */
173    if (iService < 0)
174    {
175    }
176
177    /* just possibly it's a default service? */
178    if (iService < 0) 
179    {
180      char *pdefservice = lp_defaultservice();
181      if (pdefservice && *pdefservice && 
182          !strequal(pdefservice,service) &&
183          !strstr(service,".."))
184      {
185        /*
186         * We need to do a local copy here as lp_defaultservice() 
187         * returns one of the rotating lp_string buffers that
188         * could get overwritten by the recursive find_service() call
189         * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
190         */
191        pstring defservice;
192        pstrcpy(defservice, pdefservice);
193        iService = find_service(defservice);
194        if (iService >= 0)
195        {
196          all_string_sub(service,"_","/",0);
197          iService = lp_add_service(service,iService);
198        }
199      }
200    }
201
202    if (iService >= 0)
203      if (!VALID_SNUM(iService))
204      {
205        DEBUG(0,("Invalid snum %d for %s\n",iService,service));
206        iService = -1;
207      }
208
209    if (iService < 0)
210      DEBUG(3,("find_service() failed to find service %s\n", service));
211
212    return (iService);
213 }
214
215
216 /****************************************************************************
217   make a connection to a service
218 ****************************************************************************/
219 connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode)
220 {
221         int snum;
222         struct passwd *pass = NULL;
223         BOOL guest = False;
224         BOOL force = False;
225         connection_struct *conn;
226         int ret;
227
228         strlower(service);
229
230         snum = find_service(service);
231         if (snum < 0) {
232                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
233                         DEBUG(3,("refusing IPC connection\n"));
234                         *ecode = ERRnoipc;
235                         return NULL;
236                 }
237
238                 DEBUG(0,("%s (%s) couldn't find service %s\n",
239                          remote_machine, client_addr(), service));
240                 *ecode = ERRnosuchshare;
241                 return NULL;
242         }
243
244         if (strequal(service,HOMES_NAME)) {
245                 if (*user && Get_Pwnam(user,True)) {
246                         fstring dos_username;
247                         fstrcpy(dos_username, user);
248                         unix_to_dos(dos_username, True);
249                         return(make_connection(dos_username,user,password,
250                                                pwlen,dev,vuid,ecode));
251                 }
252
253                 if(lp_security() != SEC_SHARE) {
254                         if (validated_username(vuid)) {
255                                 fstring dos_username;
256                                 fstrcpy(user,validated_username(vuid));
257                                 fstrcpy(dos_username, user);
258                                 unix_to_dos(dos_username, True);
259                                 return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
260                         }
261                 } else {
262                         /* Security = share. Try with current_user_info.smb_name
263                          * as the username.  */
264                         if(*current_user_info.smb_name) {
265                                 fstring dos_username;
266                                 fstrcpy(user,current_user_info.smb_name);
267                                 fstrcpy(dos_username, user);
268                                 unix_to_dos(dos_username, True);
269                                 return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
270                         }
271                 }
272         }
273
274         if (!lp_snum_ok(snum) || 
275             !check_access(smbd_server_fd(), 
276                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
277                 *ecode = ERRaccess;
278                 return NULL;
279         }
280
281         /* you can only connect to the IPC$ service as an ipc device */
282         if (strequal(service,"IPC$") || strequal(service,"ADMIN$"))
283                 pstrcpy(dev,"IPC");
284         
285         if (*dev == '?' || !*dev) {
286                 if (lp_print_ok(snum)) {
287                         pstrcpy(dev,"LPT1:");
288                 } else {
289                         pstrcpy(dev,"A:");
290                 }
291         }
292
293         /* if the request is as a printer and you can't print then refuse */
294         strupper(dev);
295         if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
296                 DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
297                 *ecode = ERRinvdevice;
298                 return NULL;
299         }
300
301         /* Behave as a printer if we are supposed to */
302         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
303                 pstrcpy(dev, "LPT1:");
304         }
305
306         /* lowercase the user name */
307         strlower(user);
308
309         /* add it as a possible user name if we 
310            are in share mode security */
311         if (lp_security() == SEC_SHARE) {
312                 add_session_user(service);
313         }
314
315         /* shall we let them in? */
316         if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) {
317                 DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) );
318                 *ecode = ERRbadpw;
319                 return NULL;
320         }
321   
322         conn = conn_new();
323         if (!conn) {
324                 DEBUG(0,("Couldn't find free connection.\n"));
325                 *ecode = ERRnoresource;
326                 return NULL;
327         }
328
329         /* find out some info about the user */
330         pass = smb_getpwnam(user,True);
331
332         if (pass == NULL) {
333                 DEBUG(0,( "Couldn't find account %s\n",user));
334                 *ecode = ERRbaduid;
335                 conn_free(conn);
336                 return NULL;
337         }
338
339         conn->read_only = lp_readonly(snum);
340
341
342         {
343                 pstring list;
344                 StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
345                 pstring_sub(list,"%S",service);
346
347                 if (user_in_list(user,list))
348                         conn->read_only = True;
349                 
350                 StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
351                 pstring_sub(list,"%S",service);
352                 
353                 if (user_in_list(user,list))
354                         conn->read_only = False;    
355         }
356
357         /* admin user check */
358         
359         /* JRA - original code denied admin user if the share was
360            marked read_only. Changed as I don't think this is needed,
361            but old code left in case there is a problem here.
362         */
363         if (user_in_list(user,lp_admin_users(snum)) 
364 #if 0
365             && !conn->read_only
366 #endif
367             ) {
368                 conn->admin_user = True;
369                 DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
370         } else {
371                 conn->admin_user = False;
372         }
373     
374         conn->force_user = force;
375         conn->vuid = vuid;
376         conn->uid = pass->pw_uid;
377         conn->gid = pass->pw_gid;
378         safe_strcpy(conn->client_address, client_addr(), sizeof(conn->client_address)-1);
379         conn->num_files_open = 0;
380         conn->lastused = time(NULL);
381         conn->service = snum;
382         conn->used = True;
383         conn->printer = (strncmp(dev,"LPT",3) == 0);
384         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
385         conn->dirptr = NULL;
386         conn->veto_list = NULL;
387         conn->hide_list = NULL;
388         conn->veto_oplock_list = NULL;
389         string_set(&conn->dirpath,"");
390         string_set(&conn->user,user);
391         conn->nt_user_token = NULL;
392         
393         /*
394          * If force user is true, then store the
395          * given userid and also the primary groupid
396          * of the user we're forcing.
397          */
398         
399         if (*lp_force_user(snum)) {
400                 struct passwd *pass2;
401                 pstring fuser;
402                 pstrcpy(fuser,lp_force_user(snum));
403
404                 /* Allow %S to be used by force user. */
405                 pstring_sub(fuser,"%S",service);
406
407                 pass2 = (struct passwd *)Get_Pwnam(fuser,True);
408                 if (pass2) {
409                         conn->uid = pass2->pw_uid;
410                         conn->gid = pass2->pw_gid;
411                         string_set(&conn->user,fuser);
412                         fstrcpy(user,fuser);
413                         conn->force_user = True;
414                         DEBUG(3,("Forced user %s\n",fuser));      
415                 } else {
416                         DEBUG(1,("Couldn't find user %s\n",fuser));
417                 }
418         }
419
420         /* admin users always run as uid=0 */
421         if (conn->admin_user) {
422                 conn->uid = 0;
423         }
424
425 #ifdef HAVE_GETGRNAM 
426         /*
427          * If force group is true, then override
428          * any groupid stored for the connecting user.
429          */
430         
431         if (*lp_force_group(snum)) {
432                 gid_t gid;
433                 pstring gname;
434                 pstring tmp_gname;
435                 BOOL user_must_be_member = False;
436                 
437                 StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
438
439                 if (tmp_gname[0] == '+') {
440                         user_must_be_member = True;
441                         StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
442                 } else {
443                         StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
444                 }
445                 /* default service may be a group name          */
446                 pstring_sub(gname,"%S",service);
447                 gid = nametogid(gname);
448                 
449                 if (gid != (gid_t)-1) {
450                         /*
451                          * If the user has been forced and the forced group starts
452                          * with a '+', then we only set the group to be the forced
453                          * group if the forced user is a member of that group.
454                          * Otherwise, the meaning of the '+' would be ignored.
455                          */
456                         if (conn->force_user && user_must_be_member) {
457                                 if (user_in_group_list( user, gname )) {
458                                                 conn->gid = gid;
459                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
460                                 }
461                         } else {
462                                 conn->gid = gid;
463                                 DEBUG(3,("Forced group %s\n",gname));
464                         }
465                 } else {
466                         DEBUG(1,("Couldn't find group %s\n",gname));
467                 }
468         }
469 #endif /* HAVE_GETGRNAM */
470
471         {
472                 pstring s;
473                 pstrcpy(s,lp_pathname(snum));
474                 standard_sub_conn(conn,s);
475                 string_set(&conn->connectpath,s);
476                 DEBUG(3,("Connect path is %s\n",s));
477         }
478
479         /* groups stuff added by ih */
480         conn->ngroups = 0;
481         conn->groups = NULL;
482         
483         /* Find all the groups this uid is in and
484            store them. Used by become_user() */
485         initialise_groups(conn->user, conn->uid, conn->gid); 
486         get_current_groups(&conn->ngroups,&conn->groups);
487                 
488         /* check number of connections */
489         if (!claim_connection(conn,
490                               lp_servicename(SNUM(conn)),
491                               lp_max_connections(SNUM(conn)),
492                               False)) {
493                 DEBUG(1,("too many connections - rejected\n"));
494                 *ecode = ERRnoresource;
495                 conn_free(conn);
496                 return NULL;
497         }  
498                 
499         conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
500                                               conn->ngroups, conn->groups,
501                                               guest);
502
503         /*
504          * New code to check if there's a share security descripter
505          * added from NT server manager. This is done after the
506          * smb.conf checks are done as we need a uid and token. JRA.
507          */
508
509         {
510                 BOOL can_write = share_access_check(conn, snum, vuid, FILE_WRITE_DATA);
511
512                 if (!can_write) {
513                         if (!share_access_check(conn, snum, vuid, FILE_READ_DATA)) {
514                                 /* No access, read or write. */
515                                 *ecode = ERRaccess;
516                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
517                                         service ));
518                                 conn_free(conn);
519                                 return NULL;
520                         } else {
521                                 conn->read_only = True;
522                         }
523                 }
524         }
525         /* Initialise VFS function pointers */
526
527         if (*lp_vfsobj(SNUM(conn))) {
528
529 #ifdef HAVE_LIBDL
530
531             /* Loadable object file */
532
533             if (!vfs_init_custom(conn)) {
534                 DEBUG(0, ("vfs_init failed\n"));
535                     conn_free(conn);
536                         return NULL;
537             }
538 #else
539             DEBUG(0, ("No libdl present - cannot use VFS objects\n"));
540             conn_free(conn);
541             return NULL;
542 #endif
543
544         } else {
545
546             /* Normal share - initialise with disk access functions */
547
548             vfs_init_default(conn);
549         }
550
551         /* execute any "root preexec = " line */
552         if (*lp_rootpreexec(SNUM(conn))) {
553                 pstring cmd;
554                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
555                 standard_sub_conn(conn,cmd);
556                 DEBUG(5,("cmd=%s\n",cmd));
557                 ret = smbrun(cmd,NULL);
558                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
559                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
560                         conn_free(conn);
561                         *ecode = ERRsrverror;
562                         return NULL;
563                 }
564         }
565         
566         if (!become_user(conn, conn->vuid)) {
567                 DEBUG(0,("Can't become connected user!\n"));
568                 yield_connection(conn,
569                                  lp_servicename(SNUM(conn)),
570                                  lp_max_connections(SNUM(conn)));
571                 conn_free(conn);
572                 *ecode = ERRbadpw;
573                 return NULL;
574         }
575         
576         if (vfs_ChDir(conn,conn->connectpath) != 0) {
577                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
578                          remote_machine, conn->client_address,
579                          conn->connectpath,strerror(errno)));
580                 unbecome_user();
581                 yield_connection(conn,
582                                  lp_servicename(SNUM(conn)),
583                                  lp_max_connections(SNUM(conn)));
584                 conn_free(conn);
585                 *ecode = ERRnosuchshare;
586                 return NULL;
587         }
588         
589         string_set(&conn->origpath,conn->connectpath);
590         
591 #if SOFTLINK_OPTIMISATION
592         /* resolve any soft links early */
593         {
594                 pstring s;
595                 pstrcpy(s,conn->connectpath);
596                 vfs_GetWd(conn,s);
597                 string_set(&conn->connectpath,s);
598                 vfs_ChDir(conn,conn->connectpath);
599         }
600 #endif
601         
602         add_session_user(user);
603                 
604         /* execute any "preexec = " line */
605         if (*lp_preexec(SNUM(conn))) {
606                 pstring cmd;
607                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
608                 standard_sub_conn(conn,cmd);
609                 ret = smbrun(cmd,NULL);
610                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
611                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
612                         conn_free(conn);
613                         *ecode = ERRsrverror;
614                         return NULL;
615                 }
616         }
617
618         /*
619          * Print out the 'connected as' stuff here as we need
620          * to know the effective uid and gid we will be using.
621          */
622
623         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
624                 dbgtext( "%s (%s) ", remote_machine, conn->client_address );
625                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
626                 dbgtext( "as user %s ", user );
627                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
628                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
629         }
630         
631         /* we've finished with the sensitive stuff */
632         unbecome_user();
633         
634         /* Add veto/hide lists */
635         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
636                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
637                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
638                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
639         }
640         
641         /* Invoke VFS make connection hook */
642
643         if (conn->vfs_ops.connect) {
644                 if (conn->vfs_ops.connect(conn, service, user) < 0)
645                         return NULL;
646         }
647             
648         return(conn);
649 }
650
651
652 /****************************************************************************
653 close a cnum
654 ****************************************************************************/
655 void close_cnum(connection_struct *conn, uint16 vuid)
656 {
657         DirCacheFlush(SNUM(conn));
658
659         unbecome_user();
660
661         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
662                                  remote_machine,conn->client_address,
663                                  lp_servicename(SNUM(conn))));
664
665         if (conn->vfs_ops.disconnect != NULL) {
666
667             /* Call VFS disconnect hook */
668             
669             conn->vfs_ops.disconnect(conn);
670             
671         }
672
673         yield_connection(conn,
674                          lp_servicename(SNUM(conn)),
675                          lp_max_connections(SNUM(conn)));
676
677         file_close_conn(conn);
678         dptr_closecnum(conn);
679
680         /* execute any "postexec = " line */
681         if (*lp_postexec(SNUM(conn)) && 
682             become_user(conn, vuid))  {
683                 pstring cmd;
684                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
685                 standard_sub_conn(conn,cmd);
686                 smbrun(cmd,NULL);
687                 unbecome_user();
688         }
689
690         unbecome_user();
691         /* execute any "root postexec = " line */
692         if (*lp_rootpostexec(SNUM(conn)))  {
693                 pstring cmd;
694                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
695                 standard_sub_conn(conn,cmd);
696                 smbrun(cmd,NULL);
697         }
698         conn_free(conn);
699 }