Merge of Chris's fix.
[sfrench/samba-autobuild/.git] / source / smbd / lanman.c
index 6a031dde6f89c375c8fbfd85656fe21aa4900fbd..c4df84e76c70ef265b92c622f92b7403e0585276 100644 (file)
@@ -109,14 +109,14 @@ static char* Expand(connection_struct *conn, int snum, char* s)
 /*******************************************************************
   check a API string for validity when we only need to check the prefix
   ******************************************************************/
-static BOOL prefix_ok(char *str,char *prefix)
+static BOOL prefix_ok(const char *str, const char *prefix)
 {
   return(strncmp(str,prefix,strlen(prefix)) == 0);
 }
 
 struct pack_desc {
-  char* format;            /* formatstring for structure */
-  char* subformat;  /* subformat for structure */
+  const char* format;      /* formatstring for structure */
+  const char* subformat;  /* subformat for structure */
   char* base;      /* baseaddress of buffer */
   int buflen;     /* remaining size for fixed part; on init: length of base */
   int subcount;            /* count of substructures */
@@ -125,11 +125,11 @@ struct pack_desc {
   char* stringbuf;  /* pointer into buffer for remaining variable part */
   int neededlen;    /* total needed size */
   int usedlen;     /* total used size (usedlen <= neededlen and usedlen <= buflen) */
-  char* curpos;            /* current position; pointer into format or subformat */
+  const char* curpos;      /* current position; pointer into format or subformat */
   int errcode;
 };
 
-static int get_counter(char** p)
+static int get_counter(const char** p)
 {
   int i, n;
   if (!p || !(*p)) return(1);
@@ -144,7 +144,7 @@ static int get_counter(char** p)
   }
 }
 
-static int getlen(char* p)
+static int getlen(const char* p)
 {
   int n = 0;
   if (!p) return(0);
@@ -218,7 +218,7 @@ static int package(struct pack_desc* p, ...)
 {
   va_list args;
   int needed=0, stringneeded;
-  char* str=NULL;
+  const char* str=NULL;
   int is_string=0, stringused;
   int32 temp;
 
@@ -329,12 +329,12 @@ static int package(struct pack_desc* p, ...)
 #define PACKl(desc,t,v,l) package(desc,v,l)
 #endif
 
-static void PACKI(struct pack_desc* desc,char *t,int v)
+static void PACKI(struct pack_desc* desc, const char *t,int v)
 {
   PACK(desc,t,v);
 }
 
-static void PACKS(struct pack_desc* desc,char *t,char *v)
+static void PACKS(struct pack_desc* desc,const char *t,const char *v)
 {
   PACK(desc,t,v);
 }
@@ -500,7 +500,7 @@ static BOOL get_driver_name(int snum, pstring drivername)
        NT_PRINTER_INFO_LEVEL *info = NULL;
        BOOL in_tdb = False;
 
-       get_a_printer (&info, 2, lp_servicename(snum));
+       get_a_printer (NULL, &info, 2, lp_servicename(snum));
        if (info != NULL) {
                pstrcpy( drivername, info->info_2->drivername);
                in_tdb = True;
@@ -522,7 +522,9 @@ static void fill_printq_info_52(connection_struct *conn, int snum,
        NT_PRINTER_DRIVER_INFO_LEVEL    driver;
        NT_PRINTER_INFO_LEVEL           *printer = NULL;
 
-       if ( !W_ERROR_IS_OK(get_a_printer( &printer, 2, lp_servicename(snum))) ) {
+       ZERO_STRUCT(driver);
+
+       if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
                DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n", 
                        lp_servicename(snum)));
                goto err;
@@ -679,7 +681,9 @@ static int get_printerdrivernumber(int snum)
        NT_PRINTER_DRIVER_INFO_LEVEL    driver;
        NT_PRINTER_INFO_LEVEL           *printer = NULL;
 
-       if ( !W_ERROR_IS_OK(get_a_printer( &printer, 2, lp_servicename(snum))) ) {
+       ZERO_STRUCT(driver);
+
+       if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
                DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n", 
                        lp_servicename(snum)));
                goto done;
@@ -1008,7 +1012,7 @@ static int get_server_info(uint32 servertype,
     if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
     if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
       /* this allows us to cope with an old nmbd */
-      pstrcpy(s->domain,lp_workgroup()); 
+      fstrcpy(s->domain,lp_workgroup()); 
     }
     
     if (sscanf(stype,"%X",&s->type) != 1) { 
@@ -1461,12 +1465,24 @@ static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *para
 }
 
 /****************************************************************************
-  view list of shares available
-  ****************************************************************************/
-static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
-                             int mdrcnt,int mprcnt,
-                             char **rdata,char **rparam,
-                             int *rdata_len,int *rparam_len)
+  View the list of available shares.
+
+  This function is the server side of the NetShareEnum() RAP call.
+  It fills the return buffer with share names and share comments.
+  Note that the return buffer normally (in all known cases) allows only
+  twelve byte strings for share names (plus one for a nul terminator).
+  Share names longer than 12 bytes must be skipped.
+ ****************************************************************************/
+static BOOL api_RNetShareEnum( connection_struct *conn,
+                               uint16             vuid,
+                               char              *param,
+                               char              *data,
+                               int                mdrcnt,
+                               int                mprcnt,
+                               char             **rdata,
+                               char             **rparam,
+                               int               *rdata_len,
+                               int               *rparam_len )
 {
   char *str1 = param+2;
   char *str2 = skip_string(str1,1);
@@ -1486,7 +1502,9 @@ static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,c
   
   data_len = fixed_len = string_len = 0;
   for (i=0;i<count;i++)
-    if (lp_browseable(i) && lp_snum_ok(i))
+    if( lp_browseable( i )
+        && lp_snum_ok( i )
+        && (strlen( lp_servicename( i ) ) < 13) )   /* Maximum name length. */
     {
       total++;
       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
@@ -1507,10 +1525,16 @@ static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,c
   p = *rdata;
   f_len = fixed_len;
   s_len = string_len;
-  for (i = 0; i < count;i++)
-    if (lp_browseable(i) && lp_snum_ok(i))
-      if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
+  for( i = 0; i < count; i++ )
+    {
+    if( lp_browseable( i )
+        && lp_snum_ok( i )
+        && (strlen( lp_servicename( i ) ) < 13) )
+      {
+      if( fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0 )
        break;
+      }
+    }
   
   *rparam_len = 8;
   *rparam = REALLOC(*rparam,*rparam_len);
@@ -1523,7 +1547,7 @@ static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,c
           counted,total,uLevel,
           buf_len,*rdata_len,mdrcnt));
   return(True);
-}
+} /* api_RNetShareEnum */
 
 /****************************************************************************
   Add a share
@@ -1631,6 +1655,7 @@ static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,c
        char *str1 = param+2;
        char *str2 = skip_string(str1,1);
        char *p = skip_string(str2,1);
+       BOOL ret;
 
        GROUP_MAP *group_list;
        int num_entries;
@@ -1649,8 +1674,12 @@ static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,c
                return False;
 
        /* get list of domain groups SID_DOMAIN_GRP=2 */
-       if(!pdb_enum_group_mapping(SID_NAME_DOM_GRP , &group_list, &num_entries, False, False)) {
-               DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
+       become_root();
+       ret = pdb_enum_group_mapping(SID_NAME_DOM_GRP , &group_list, &num_entries, False);
+       unbecome_root();
+       
+       if( !ret ) {
+               DEBUG(3,("api_RNetGroupEnum:failed to get group list"));        
                return False;
        }
 
@@ -1704,24 +1733,35 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para
        char *UserName = skip_string(str2,1);
        char *p = skip_string(UserName,1);
        int uLevel = SVAL(p,0);
-       char *p2;
+       const char *level_string;
        int count=0;
+       SAM_ACCOUNT *sampw = NULL;
+       BOOL ret = False;
+        DOM_GID *gids = NULL;
+        int num_groups = 0;
+       int i;
+       fstring grp_domain;
+       fstring grp_name;
+       enum SID_NAME_USE grp_type;
+       DOM_SID sid, dom_sid;
 
        *rparam_len = 8;
        *rparam = REALLOC(*rparam,*rparam_len);
   
        /* check it's a supported varient */
-       if (!strcmp(str1,"zWrLeh"))
+       
+       if ( strcmp(str1,"zWrLeh") != 0 )
                return False;
+               
        switch( uLevel ) {
                case 0:
-                       p2 = "B21";
+                       level_string = "B21";
                        break;
                default:
                        return False;
        }
 
-       if (strcmp(p2,str2) != 0)
+       if (strcmp(level_string,str2) != 0)
                return False;
 
        *rdata_len = mdrcnt + 1024;
@@ -1732,18 +1772,59 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para
 
        p = *rdata;
 
-       /* XXXX we need a real SAM database some day */
-       pstrcpy(p,"Users"); p += 21; count++;
-       pstrcpy(p,"Domain Users"); p += 21; count++;
-       pstrcpy(p,"Guests"); p += 21; count++;
-       pstrcpy(p,"Domain Guests"); p += 21; count++;
+       /* Lookup the user information; This should only be one of 
+          our accounts (not remote domains) */
+          
+       pdb_init_sam( &sampw );
+       
+       become_root();                                  /* ROOT BLOCK */
+
+       if ( !pdb_getsampwnam(sampw, UserName) )
+               goto out;
+
+       /* this next set of code is horribly inefficient, but since 
+          it is rarely called, I'm going to leave it like this since 
+          it easier to follow      --jerry                          */
+          
+       /* get the list of group SIDs */
+       
+       if ( !get_domain_user_groups(conn->mem_ctx, &num_groups, &gids, sampw) ) {
+               DEBUG(1,("api_NetUserGetGroups: get_domain_user_groups() failed!\n"));
+               goto out;
+        }
 
+       /* convert to names (we don't support universal groups so the domain
+          can only be ours) */
+       
+       sid_copy( &dom_sid, get_global_sam_sid() );
+       for (i=0; i<num_groups; i++) {
+       
+               /* make the DOM_GID into a DOM_SID and then lookup 
+                  the name */
+               
+               sid_copy( &sid, &dom_sid );
+               sid_append_rid( &sid, gids[i].g_rid );
+               
+               if ( lookup_sid(&sid, grp_domain, grp_name, &grp_type) ) {
+                       pstrcpy(p, grp_name); 
+                       p += 21; 
+                       count++;
+               }
+       }
+       
        *rdata_len = PTR_DIFF(p,*rdata);
 
        SSVAL(*rparam,4,count); /* is this right?? */
        SSVAL(*rparam,6,count); /* is this right?? */
 
-       return(True);
+       ret = True;
+
+out:
+       unbecome_root();                                /* END ROOT BLOCK */
+
+       pdb_free_sam( &sampw );
+
+       return ret;
 }
 
 /*******************************************************************
@@ -1897,94 +1978,78 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
                                char **rdata,char **rparam,
                                int *rdata_len,int *rparam_len)
 {
-  char *p = skip_string(param+2,2);
-  fstring user;
-  fstring pass1,pass2;
+       char *p = skip_string(param+2,2);
+       fstring user;
+       fstring pass1,pass2;
 
-  pull_ascii_fstring(user,p);
+       pull_ascii_fstring(user,p);
 
-  p = skip_string(p,1);
+       p = skip_string(p,1);
 
-  memset(pass1,'\0',sizeof(pass1));
-  memset(pass2,'\0',sizeof(pass2));
-  memcpy(pass1,p,16);
-  memcpy(pass2,p+16,16);
+       memset(pass1,'\0',sizeof(pass1));
+       memset(pass2,'\0',sizeof(pass2));
+       memcpy(pass1,p,16);
+       memcpy(pass2,p+16,16);
 
-  *rparam_len = 4;
-  *rparam = REALLOC(*rparam,*rparam_len);
+       *rparam_len = 4;
+       *rparam = REALLOC(*rparam,*rparam_len);
 
-  *rdata_len = 0;
+       *rdata_len = 0;
 
-  SSVAL(*rparam,0,NERR_badpass);
-  SSVAL(*rparam,2,0);          /* converter word */
+       SSVAL(*rparam,0,NERR_badpass);
+       SSVAL(*rparam,2,0);             /* converter word */
 
-  DEBUG(3,("Set password for <%s>\n",user));
+       DEBUG(3,("Set password for <%s>\n",user));
 
-  /*
-   * Attempt to verify the old password against smbpasswd entries
-   * Win98 clients send old and new password in plaintext for this call.
-   */
+       /*
+        * Attempt to verify the old password against smbpasswd entries
+        * Win98 clients send old and new password in plaintext for this call.
+        */
 
-  {
-         auth_serversupplied_info *server_info = NULL;
-         DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
-         if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
-
-                 /*
-                  * If unix password sync was requested, attempt to change
-                  * the /etc/passwd database first. Return failure if this cannot
-                  * be done.
-                  *
-                  * This occurs before the oem change, becouse we don't want to
-                   * update it if chgpasswd failed.
-                  *
-                  * Conditional on lp_unix_password_sync() becouse we don't want
-                   * to touch the unix db unless we have admin permission.
-                  */
-                 
-                 if(lp_unix_password_sync() && IS_SAM_UNIX_USER(server_info->sam_account) 
-                    && !chgpasswd(pdb_get_username(server_info->sam_account),
-                                  pass1,pass2,False)) {
-                         SSVAL(*rparam,0,NERR_badpass);
-                 }
-                 
-                 if (change_oem_password(server_info->sam_account,pass2))
-                 {
-                         SSVAL(*rparam,0,NERR_Success);
-                 }
-                 
-                 free_server_info(&server_info);
-         }
-         data_blob_clear_free(&password);
-  }
+       {
+               auth_serversupplied_info *server_info = NULL;
+               DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
 
-  /*
-   * If the plaintext change failed, attempt
-   * the old encrypted method. NT will generate this
-   * after trying the samr method. Note that this
-   * method is done as a last resort as this
-   * password change method loses the NT password hash
-   * and cannot change the UNIX password as no plaintext
-   * is received.
-   */
+               if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
 
-  if(SVAL(*rparam,0) != NERR_Success)
-  {
-    SAM_ACCOUNT *hnd = NULL;
+                       become_root();
+                       if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False))) {
+                               SSVAL(*rparam,0,NERR_Success);
+                       }
+                       unbecome_root();
 
-    if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) && 
-       change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
-    {
-      SSVAL(*rparam,0,NERR_Success);
-    }
-       pdb_free_sam(&hnd);
-  }
+                       free_server_info(&server_info);
+               }
+               data_blob_clear_free(&password);
+       }
 
+       /*
+        * If the plaintext change failed, attempt
+        * the old encrypted method. NT will generate this
+        * after trying the samr method. Note that this
+        * method is done as a last resort as this
+        * password change method loses the NT password hash
+        * and cannot change the UNIX password as no plaintext
+        * is received.
+        */
+
+       if(SVAL(*rparam,0) != NERR_Success) {
+               SAM_ACCOUNT *hnd = NULL;
+
+               if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
+                       become_root();
+                       if (change_lanman_password(hnd,(uchar *)pass2)) {
+                               SSVAL(*rparam,0,NERR_Success);
+                       }
+                       unbecome_root();
+                       pdb_free_sam(&hnd);
+               }
+       }
 
-  memset((char *)pass1,'\0',sizeof(fstring));
-  memset((char *)pass2,'\0',sizeof(fstring));   
+       memset((char *)pass1,'\0',sizeof(fstring));
+       memset((char *)pass2,'\0',sizeof(fstring));      
         
-  return(True);
+       return(True);
 }
 
 /****************************************************************************
@@ -1996,47 +2061,46 @@ static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *
                                char **rdata,char **rparam,
                                int *rdata_len,int *rparam_len)
 {
-  fstring user;
-  char *p = param + 2;
-  *rparam_len = 2;
-  *rparam = REALLOC(*rparam,*rparam_len);
+       fstring user;
+       char *p = param + 2;
+       *rparam_len = 2;
+       *rparam = REALLOC(*rparam,*rparam_len);
 
-  *rdata_len = 0;
+       *rdata_len = 0;
 
-  SSVAL(*rparam,0,NERR_badpass);
+       SSVAL(*rparam,0,NERR_badpass);
 
-  /*
-   * Check the parameter definition is correct.
-   */
-  if(!strequal(param + 2, "zsT")) {
-    DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
-    return False;
-  }
-  p = skip_string(p, 1);
+       /*
+        * Check the parameter definition is correct.
+        */
 
-  if(!strequal(p, "B516B16")) {
-    DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
-    return False;
-  }
-  p = skip_string(p,1);
+       if(!strequal(param + 2, "zsT")) {
+               DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
+               return False;
+       }
+       p = skip_string(p, 1);
 
-  p += pull_ascii_fstring(user,p);
+       if(!strequal(p, "B516B16")) {
+               DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
+               return False;
+       }
+       p = skip_string(p,1);
+       p += pull_ascii_fstring(user,p);
 
-  DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
+       DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
 
-  /*
-   * Pass the user through the NT -> unix user mapping
-   * function.
-   */
+       /*
+        * Pass the user through the NT -> unix user mapping
+        * function.
+        */
 
-  (void)map_username(user);
+       (void)map_username(user);
 
-  if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
-  {
-    SSVAL(*rparam,0,NERR_Success);
-  }
+       if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))) {
+               SSVAL(*rparam,0,NERR_Success);
+       }
 
-  return(True);
+       return(True);
 }
 
 /****************************************************************************
@@ -2307,15 +2371,15 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par
       pstring comment;
       uint32 servertype= lp_default_server_announce();
 
-      pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+      push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
 
       if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
-       for (i=0;i<count;i++)
-         if (strequal(servers[i].name,local_machine))
-      {
+       for (i=0;i<count;i++) {
+         if (strequal(servers[i].name,local_machine)) {
            servertype = servers[i].type;
-           pstrcpy(comment,servers[i].comment);            
+           push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);           
          }
+       }
       }
       SAFE_FREE(servers);
 
@@ -2385,7 +2449,7 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param
 
   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
   pstrcpy(p2,local_machine);
-  strupper(p2);
+  strupper_m(p2);
   p2 = skip_string(p2,1);
   p += 4;
 
@@ -2396,7 +2460,7 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param
 
   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
   pstrcpy(p2,lp_workgroup());
-  strupper(p2);
+  strupper_m(p2);
   p2 = skip_string(p2,1);
   p += 4;
 
@@ -2602,6 +2666,7 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param
        char *p = skip_string(UserName,1);
        int uLevel = SVAL(p,0);
        char *p2;
+       const char *level_string;
 
     /* get NIS home of a previously validated user - simeon */
     /* With share level security vuid will always be zero.
@@ -2620,15 +2685,15 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param
        if (strcmp(str1,"zWrLh") != 0) return False;
        switch( uLevel )
        {
-               case 0: p2 = "B21"; break;
-               case 1: p2 = "B21BB16DWzzWz"; break;
-               case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
-               case 10: p2 = "B21Bzzz"; break;
-               case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
+               case 0: level_string = "B21"; break;
+               case 1: level_string = "B21BB16DWzzWz"; break;
+               case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
+               case 10: level_string = "B21Bzzz"; break;
+               case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
                default: return False;
        }
 
-       if (strcmp(p2,str2) != 0) return False;
+       if (strcmp(level_string,str2) != 0) return False;
 
        *rdata_len = mdrcnt + 1024;
        *rdata = REALLOC(*rdata,*rdata_len);
@@ -2805,7 +2870,7 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param
       fstring mypath;
       fstrcpy(mypath,"\\\\");
       fstrcat(mypath,local_machine);
-      strupper(mypath);
+      strupper_m(mypath);
       PACKS(&desc,"z",mypath); /* computer */
     }
     PACKS(&desc,"z",lp_workgroup());/* domain */
@@ -3024,7 +3089,7 @@ static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
   char buf[100];
   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
   buf[sizeof(buf)-1] = 0;
-  strupper(buf);
+  strupper_m(buf);
   if (uLevel <= 1) {
     PACKS(desc,"B9",buf);      /* szName */
     if (uLevel == 1) {
@@ -3425,9 +3490,9 @@ static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,cha
 
 
 
-const static struct
+static const struct
 {
-  char *name;
+  const char *name;
   int id;
   BOOL (*fn)(connection_struct *,uint16,char *,char *,
             int,int,char **,char **,int *,int *);