[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / smbd / service.c
index 8dbcc2b5abe622c44ea60ca3ae9e78b21024aab5..1c46e3776c28442e94b6fc77770d61c314d4c86f 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
@@ -53,7 +52,7 @@ static BOOL canonicalize_path(connection_struct *conn, pstring path)
  Observent people will notice a similarity between this and check_path_syntax :-).
 ****************************************************************************/
 
-void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
+void set_conn_connectpath(connection_struct *conn, const char *connectpath)
 {
        pstring destname;
        char *d = destname;
@@ -313,6 +312,7 @@ static int load_registry_service(const char *servicename)
                TALLOC_FREE(value);
        }
 
+       res = 0;
  error:
 
        TALLOC_FREE(key);
@@ -402,6 +402,17 @@ int find_service(fstring service)
        if (iService < 0) {
        }
 
+       if (iService < 0) {
+               iService = load_registry_service(service);
+       }
+
+       /* Is it a usershare service ? */
+       if (iService < 0 && *lp_usershare_path()) {
+               /* Ensure the name is canonicalized. */
+               strlower_m(service);
+               iService = load_usershare_service(service);
+       }
+
        /* just possibly it's a default service? */
        if (iService < 0) {
                char *pdefservice = lp_defaultservice();
@@ -414,6 +425,14 @@ int find_service(fstring service)
                         */
                        pstring defservice;
                        pstrcpy(defservice, pdefservice);
+
+                       /* Disallow anything except explicit share names. */
+                       if (strequal(defservice,HOMES_NAME) ||
+                                       strequal(defservice, PRINTERS_NAME) ||
+                                       strequal(defservice, "IPC$")) {
+                               goto fail;
+                       }
+
                        iService = find_service(defservice);
                        if (iService >= 0) {
                                all_string_sub(service, "_","/",0);
@@ -422,17 +441,6 @@ int find_service(fstring service)
                }
        }
 
-       if (iService < 0) {
-               iService = load_registry_service(service);
-       }
-
-       /* Is it a usershare service ? */
-       if (iService < 0 && *lp_usershare_path()) {
-               /* Ensure the name is canonicalized. */
-               strlower_m(service);
-               iService = load_usershare_service(service);
-       }
-
        if (iService >= 0) {
                if (!VALID_SNUM(iService)) {
                        DEBUG(0,("Invalid snum %d for %s\n",iService, service));
@@ -440,6 +448,8 @@ int find_service(fstring service)
                }
        }
 
+  fail:
+
        if (iService < 0)
                DEBUG(3,("find_service() failed to find service %s\n", service));
 
@@ -898,10 +908,28 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
         */
 
        {
+               BOOL can_write = False;
                NT_USER_TOKEN *token = conn->nt_user_token ?
-                       conn->nt_user_token : vuser->nt_user_token;
+                       conn->nt_user_token :
+                       (vuser ? vuser->nt_user_token : NULL);
+
+               /*
+                * I don't believe this can happen. But the
+                * logic above is convoluted enough to confuse
+                * automated checkers, so be sure. JRA.
+                */
+
+               if (token == NULL) {
+                       DEBUG(0,("make_connection: connection to %s "
+                                "denied due to missing "
+                                "NT token.\n",
+                                 lp_servicename(snum)));
+                       conn_free(conn);
+                       *status = NT_STATUS_ACCESS_DENIED;
+                       return NULL;
+               }
 
-               BOOL can_write = share_access_check(token,
+               can_write = share_access_check(token,
                                                    lp_servicename(snum),
                                                    FILE_WRITE_DATA);
 
@@ -950,21 +978,35 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                conn->notify_ctx = notify_init(conn->mem_ctx, server_id_self(),
                                               smbd_messaging_context(),
                                               smbd_event_context(),
-                                              conn->params);
+                                              conn);
        }
 
 /* ROOT Activities: */ 
-       /* check number of connections */
-       if (!claim_connection(conn,
-                             lp_servicename(snum),
-                             lp_max_connections(snum),
-                             False,0)) {
-               DEBUG(1,("too many connections - rejected\n"));
+       /*
+        * Enforce the max connections parameter.
+        */
+
+       if ((lp_max_connections(snum) > 0)
+           && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
+               lp_max_connections(snum))) {
+
+               DEBUG(1, ("Max connections (%d) exceeded for %s\n",
+                         lp_max_connections(snum), lp_servicename(snum)));
                conn_free(conn);
                *status = NT_STATUS_INSUFFICIENT_RESOURCES;
                return NULL;
        }  
 
+       /*
+        * Get us an entry in the connections db
+        */
+       if (!claim_connection(conn, lp_servicename(snum), 0)) {
+               DEBUG(1, ("Could not store connections entry\n"));
+               conn_free(conn);
+               *status = NT_STATUS_INTERNAL_DB_ERROR;
+               return NULL;
+       }  
+
        /* Preexecs are done here as they might make the dir we are to ChDir
         * to below */
        /* execute any "root preexec = " line */
@@ -1069,27 +1111,31 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                                 strerror(errno) ));
                }
                change_to_root_user();
-               /* Call VFS disconnect hook */    
+               /* Call VFS disconnect hook */
                SMB_VFS_DISCONNECT(conn);
                yield_connection(conn, lp_servicename(snum));
                conn_free(conn);
                *status = NT_STATUS_BAD_NETWORK_NAME;
                return NULL;
        }
-       
+
        string_set(&conn->origpath,conn->connectpath);
-       
+
 #if SOFTLINK_OPTIMISATION
        /* resolve any soft links early if possible */
        if (vfs_ChDir(conn,conn->connectpath) == 0) {
-               pstring s;
-               pstrcpy(s,conn->connectpath);
-               vfs_GetWd(conn,s);
+               TALLOC_CTX *ctx = talloc_stackframe();
+               char *s = vfs_GetWd(ctx,s);
+               if (!s) {
+                       *status = map_nt_error_from_unix(errno);
+                       return NULL;
+               }
                set_conn_connectpath(conn,s);
                vfs_ChDir(conn,conn->connectpath);
+               TALLOC_FREE(ctx);
        }
 #endif
-       
+
        /*
         * Print out the 'connected as' stuff here as we need
         * to know the effective uid and gid we will be using
@@ -1105,7 +1151,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
                dbgtext( "(pid %d)\n", (int)sys_getpid() );
        }
-       
+
        /* we've finished with the user stuff - go back to root */
        change_to_root_user();
        return(conn);
@@ -1195,7 +1241,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password,
 
        if (strequal(service_in,HOMES_NAME)) {
                if(lp_security() != SEC_SHARE) {
-                       DATA_BLOB no_pw = data_blob(NULL, 0);
+                       DATA_BLOB no_pw = data_blob_null;
                        if (vuser->homes_snum == -1) {
                                DEBUG(2, ("[homes] share not available for "
                                          "this user because it was not found "
@@ -1231,7 +1277,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password,
        } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
                   && strequal(service_in,
                               lp_servicename(vuser->homes_snum))) {
-               DATA_BLOB no_pw = data_blob(NULL, 0);
+               DATA_BLOB no_pw = data_blob_null;
                DEBUG(5, ("making a connection to 'homes' service [%s] "
                          "created at session setup time\n", service_in));
                return make_connection_snum(vuser->homes_snum,