Convert other parameters (read list, write list, valid users...) to the P_LIST format.
[ira/wip.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_m(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                         return(make_connection(dos_username,user,password,
249                                                pwlen,dev,vuid,ecode));
250                 }
251
252                 if(lp_security() != SEC_SHARE) {
253                         if (validated_username(vuid)) {
254                                 fstring dos_username;
255                                 fstrcpy(user,validated_username(vuid));
256                                 fstrcpy(dos_username, user);
257                                 return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
258                         }
259                 } else {
260                         /* Security = share. Try with current_user_info.smb_name
261                          * as the username.  */
262                         if(*current_user_info.smb_name) {
263                                 fstring dos_username;
264                                 fstrcpy(user,current_user_info.smb_name);
265                                 fstrcpy(dos_username, user);
266                                 return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
267                         }
268                 }
269         }
270
271         if (!lp_snum_ok(snum) || 
272             !check_access(smbd_server_fd(), 
273                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
274                 *ecode = ERRaccess;
275                 return NULL;
276         }
277
278         /* you can only connect to the IPC$ service as an ipc device */
279         if (strequal(service,"IPC$") || strequal(service,"ADMIN$"))
280                 pstrcpy(dev,"IPC");
281         
282         if (*dev == '?' || !*dev) {
283                 if (lp_print_ok(snum)) {
284                         pstrcpy(dev,"LPT1:");
285                 } else {
286                         pstrcpy(dev,"A:");
287                 }
288         }
289
290         /* if the request is as a printer and you can't print then refuse */
291         strupper(dev);
292         if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
293                 DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
294                 *ecode = ERRinvdevice;
295                 return NULL;
296         }
297
298         /* Behave as a printer if we are supposed to */
299         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
300                 pstrcpy(dev, "LPT1:");
301         }
302
303         /* lowercase the user name */
304         strlower(user);
305
306         /* add it as a possible user name if we 
307            are in share mode security */
308         if (lp_security() == SEC_SHARE) {
309                 add_session_user(service);
310         }
311
312         /* shall we let them in? */
313         if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) {
314                 DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) );
315                 *ecode = ERRbadpw;
316                 return NULL;
317         }
318   
319         conn = conn_new();
320         if (!conn) {
321                 DEBUG(0,("Couldn't find free connection.\n"));
322                 *ecode = ERRnoresource;
323                 return NULL;
324         }
325
326         /* find out some info about the user */
327         pass = smb_getpwnam(user,True);
328
329         if (pass == NULL) {
330                 DEBUG(0,( "Couldn't find account %s\n",user));
331                 *ecode = ERRbaduid;
332                 conn_free(conn);
333                 return NULL;
334         }
335
336         conn->read_only = lp_readonly(snum);
337
338
339         {
340                 char **list;
341
342                 lp_list_copy(&list, lp_readlist(snum));
343                 if(list && lp_list_substitute(list, "%S", service)) {
344                         if (user_in_list(user, list))
345                                 conn->read_only = True;
346                 }
347                 else DEBUG(0, ("read list substitution failed readlist: 0x%x list: 0x%x\n", lp_readlist(snum), list));
348                 if (list) lp_list_free(&list);
349
350                 lp_list_copy(&list, lp_writelist(snum));
351                 if(list && lp_list_substitute(list, "%S", service)) {
352                         if (user_in_list(user, list))
353                                 conn->read_only = False;
354                 }
355                 else DEBUG(0, ("write list substitution failed writelist: 0x%x list: 0x%x\n", lp_writelist(snum), list));
356                 if (list) lp_list_free(&list);
357         }
358
359         /* admin user check */
360         
361         /* JRA - original code denied admin user if the share was
362            marked read_only. Changed as I don't think this is needed,
363            but old code left in case there is a problem here.
364         */
365         if (user_in_list(user, lp_admin_users(snum)) 
366 #if 0
367             && !conn->read_only
368 #endif
369             ) {
370                 conn->admin_user = True;
371                 DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
372         } else {
373                 conn->admin_user = False;
374         }
375     
376         conn->force_user = force;
377         conn->vuid = vuid;
378         conn->uid = pass->pw_uid;
379         conn->gid = pass->pw_gid;
380         safe_strcpy(conn->client_address, client_addr(), sizeof(conn->client_address)-1);
381         conn->num_files_open = 0;
382         conn->lastused = time(NULL);
383         conn->service = snum;
384         conn->used = True;
385         conn->printer = (strncmp(dev,"LPT",3) == 0);
386         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
387         conn->dirptr = NULL;
388         conn->veto_list = NULL;
389         conn->hide_list = NULL;
390         conn->veto_oplock_list = NULL;
391         string_set(&conn->dirpath,"");
392         string_set(&conn->user,user);
393         conn->nt_user_token = NULL;
394         
395         /*
396          * If force user is true, then store the
397          * given userid and also the primary groupid
398          * of the user we're forcing.
399          */
400         
401         if (*lp_force_user(snum)) {
402                 struct passwd *pass2;
403                 pstring fuser;
404                 pstrcpy(fuser,lp_force_user(snum));
405
406                 /* Allow %S to be used by force user. */
407                 pstring_sub(fuser,"%S",service);
408
409                 pass2 = (struct passwd *)Get_Pwnam(fuser,True);
410                 if (pass2) {
411                         conn->uid = pass2->pw_uid;
412                         conn->gid = pass2->pw_gid;
413                         string_set(&conn->user,fuser);
414                         fstrcpy(user,fuser);
415                         conn->force_user = True;
416                         DEBUG(3,("Forced user %s\n",fuser));      
417                 } else {
418                         DEBUG(1,("Couldn't find user %s\n",fuser));
419                 }
420         }
421
422         /* admin users always run as uid=0 */
423         if (conn->admin_user) {
424                 conn->uid = 0;
425         }
426
427 #ifdef HAVE_GETGRNAM 
428         /*
429          * If force group is true, then override
430          * any groupid stored for the connecting user.
431          */
432         
433         if (*lp_force_group(snum)) {
434                 gid_t gid;
435                 pstring gname;
436                 pstring tmp_gname;
437                 BOOL user_must_be_member = False;
438                 
439                 StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
440
441                 if (tmp_gname[0] == '+') {
442                         user_must_be_member = True;
443                         StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
444                 } else {
445                         StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
446                 }
447                 /* default service may be a group name          */
448                 pstring_sub(gname,"%S",service);
449                 gid = nametogid(gname);
450                 
451                 if (gid != (gid_t)-1) {
452                         /*
453                          * If the user has been forced and the forced group starts
454                          * with a '+', then we only set the group to be the forced
455                          * group if the forced user is a member of that group.
456                          * Otherwise, the meaning of the '+' would be ignored.
457                          */
458                         if (conn->force_user && user_must_be_member) {
459                                 if (user_in_group_list( user, gname )) {
460                                                 conn->gid = gid;
461                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
462                                 }
463                         } else {
464                                 conn->gid = gid;
465                                 DEBUG(3,("Forced group %s\n",gname));
466                         }
467                 } else {
468                         DEBUG(1,("Couldn't find group %s\n",gname));
469                 }
470         }
471 #endif /* HAVE_GETGRNAM */
472
473         {
474                 pstring s;
475                 pstrcpy(s,lp_pathname(snum));
476                 standard_sub_conn(conn,s);
477                 string_set(&conn->connectpath,s);
478                 DEBUG(3,("Connect path is %s\n",s));
479         }
480
481         /* groups stuff added by ih */
482         conn->ngroups = 0;
483         conn->groups = NULL;
484         
485         /* Find all the groups this uid is in and
486            store them. Used by become_user() */
487         initialise_groups(conn->user, conn->uid, conn->gid); 
488         get_current_groups(&conn->ngroups,&conn->groups);
489                 
490         /* check number of connections */
491         if (!claim_connection(conn,
492                               lp_servicename(SNUM(conn)),
493                               lp_max_connections(SNUM(conn)),
494                               False)) {
495                 DEBUG(1,("too many connections - rejected\n"));
496                 *ecode = ERRnoresource;
497                 conn_free(conn);
498                 return NULL;
499         }  
500                 
501         conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
502                                               conn->ngroups, conn->groups,
503                                               guest);
504
505         /*
506          * New code to check if there's a share security descripter
507          * added from NT server manager. This is done after the
508          * smb.conf checks are done as we need a uid and token. JRA.
509          */
510
511         {
512                 BOOL can_write = share_access_check(conn, snum, vuid, FILE_WRITE_DATA);
513
514                 if (!can_write) {
515                         if (!share_access_check(conn, snum, vuid, FILE_READ_DATA)) {
516                                 /* No access, read or write. */
517                                 *ecode = ERRaccess;
518                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
519                                         service ));
520                                 yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
521                                 conn_free(conn);
522                                 return NULL;
523                         } else {
524                                 conn->read_only = True;
525                         }
526                 }
527         }
528         /* Initialise VFS function pointers */
529
530         if (!vfs_init(conn)) {
531                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
532                 yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
533                 conn_free(conn);
534                 return NULL;
535         }
536
537         /* execute any "root preexec = " line */
538         if (*lp_rootpreexec(SNUM(conn))) {
539                 pstring cmd;
540                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
541                 standard_sub_conn(conn,cmd);
542                 DEBUG(5,("cmd=%s\n",cmd));
543                 ret = smbrun(cmd,NULL);
544                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
545                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
546                         yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
547                         conn_free(conn);
548                         *ecode = ERRsrverror;
549                         return NULL;
550                 }
551         }
552         
553         if (!become_user(conn, conn->vuid)) {
554                 DEBUG(0,("Can't become connected user!\n"));
555                 yield_connection(conn,
556                                  lp_servicename(SNUM(conn)),
557                                  lp_max_connections(SNUM(conn)));
558                 conn_free(conn);
559                 *ecode = ERRbadpw;
560                 return NULL;
561         }
562         
563         if (vfs_ChDir(conn,conn->connectpath) != 0) {
564                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
565                          remote_machine, conn->client_address,
566                          conn->connectpath,strerror(errno)));
567                 unbecome_user();
568                 yield_connection(conn,
569                                  lp_servicename(SNUM(conn)),
570                                  lp_max_connections(SNUM(conn)));
571                 conn_free(conn);
572                 *ecode = ERRnosuchshare;
573                 return NULL;
574         }
575         
576         string_set(&conn->origpath,conn->connectpath);
577         
578 #if SOFTLINK_OPTIMISATION
579         /* resolve any soft links early */
580         {
581                 pstring s;
582                 pstrcpy(s,conn->connectpath);
583                 vfs_GetWd(conn,s);
584                 string_set(&conn->connectpath,s);
585                 vfs_ChDir(conn,conn->connectpath);
586         }
587 #endif
588         
589         add_session_user(user);
590                 
591         /* execute any "preexec = " line */
592         if (*lp_preexec(SNUM(conn))) {
593                 pstring cmd;
594                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
595                 standard_sub_conn(conn,cmd);
596                 ret = smbrun(cmd,NULL);
597                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
598                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
599                         yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
600                         conn_free(conn);
601                         *ecode = ERRsrverror;
602                         return NULL;
603                 }
604         }
605
606         /*
607          * Print out the 'connected as' stuff here as we need
608          * to know the effective uid and gid we will be using.
609          */
610
611         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
612                 dbgtext( "%s (%s) ", remote_machine, conn->client_address );
613                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
614                 dbgtext( "as user %s ", user );
615                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
616                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
617         }
618         
619         /* we've finished with the sensitive stuff */
620         unbecome_user();
621         
622         /* Add veto/hide lists */
623         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
624                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
625                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
626                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
627         }
628         
629         /* Invoke VFS make connection hook */
630
631         if (conn->vfs_ops.connect) {
632                 if (conn->vfs_ops.connect(conn, service, user) < 0)
633                         return NULL;
634         }
635             
636         return(conn);
637 }
638
639
640 /****************************************************************************
641 close a cnum
642 ****************************************************************************/
643 void close_cnum(connection_struct *conn, uint16 vuid)
644 {
645         DirCacheFlush(SNUM(conn));
646
647         unbecome_user();
648
649         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
650                                  remote_machine,conn->client_address,
651                                  lp_servicename(SNUM(conn))));
652
653         if (conn->vfs_ops.disconnect != NULL) {
654
655             /* Call VFS disconnect hook */
656             
657             conn->vfs_ops.disconnect(conn);
658             
659         }
660
661         yield_connection(conn,
662                          lp_servicename(SNUM(conn)),
663                          lp_max_connections(SNUM(conn)));
664
665         file_close_conn(conn);
666         dptr_closecnum(conn);
667
668         /* execute any "postexec = " line */
669         if (*lp_postexec(SNUM(conn)) && 
670             become_user(conn, vuid))  {
671                 pstring cmd;
672                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
673                 standard_sub_conn(conn,cmd);
674                 smbrun(cmd,NULL);
675                 unbecome_user();
676         }
677
678         unbecome_user();
679         /* execute any "root postexec = " line */
680         if (*lp_rootpostexec(SNUM(conn)))  {
681                 pstring cmd;
682                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
683                 standard_sub_conn(conn,cmd);
684                 smbrun(cmd,NULL);
685         }
686         conn_free(conn);
687 }
688
689