smbd/posix_acls.c

説明を見る。
00001 /*
00002    Unix SMB/CIFS implementation.
00003    SMB NT Security Descriptor / Unix permission conversion.
00004    Copyright (C) Jeremy Allison 1994-2000.
00005    Copyright (C) Andreas Gruenbacher 2002.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 */
00021 
00022 #include "includes.h"
00023 
00024 extern struct current_user current_user;
00025 extern struct generic_mapping file_generic_mapping;
00026 
00027 #undef  DBGC_CLASS
00028 #define DBGC_CLASS DBGC_ACLS
00029 
00030 /****************************************************************************
00031  Data structures representing the internal ACE format.
00032 ****************************************************************************/
00033 
00034 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
00035 enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
00036 
00037 typedef union posix_id {
00038                 uid_t uid;
00039                 gid_t gid;
00040                 int world;
00041 } posix_id;
00042 
00043 typedef struct canon_ace {
00044         struct canon_ace *next, *prev;
00045         SMB_ACL_TAG_T type;
00046         mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
00047         DOM_SID trustee;
00048         enum ace_owner owner_type;
00049         enum ace_attribute attr;
00050         posix_id unix_ug;
00051         BOOL inherited;
00052 } canon_ace;
00053 
00054 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
00055 
00056 /*
00057  * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
00058  * attribute on disk.
00059  *
00060  * |  1   |  1   |   2         |         2           |  .... 
00061  * +------+------+-------------+---------------------+-------------+--------------------+
00062  * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
00063  * +------+------+-------------+---------------------+-------------+--------------------+
00064  */
00065 
00066 #define PAI_VERSION_OFFSET      0
00067 #define PAI_FLAG_OFFSET         1
00068 #define PAI_NUM_ENTRIES_OFFSET  2
00069 #define PAI_NUM_DEFAULT_ENTRIES_OFFSET  4
00070 #define PAI_ENTRIES_BASE        6
00071 
00072 #define PAI_VERSION             1
00073 #define PAI_ACL_FLAG_PROTECTED  0x1
00074 #define PAI_ENTRY_LENGTH        5
00075 
00076 /*
00077  * In memory format of user.SAMBA_PAI attribute.
00078  */
00079 
00080 struct pai_entry {
00081         struct pai_entry *next, *prev;
00082         enum ace_owner owner_type;
00083         posix_id unix_ug; 
00084 };
00085         
00086 struct pai_val {
00087         BOOL pai_protected;
00088         unsigned int num_entries;
00089         struct pai_entry *entry_list;
00090         unsigned int num_def_entries;
00091         struct pai_entry *def_entry_list;
00092 };
00093 
00094 /************************************************************************
00095  Return a uint32 of the pai_entry principal.
00096 ************************************************************************/
00097 
00098 static uint32 get_pai_entry_val(struct pai_entry *paie)
00099 {
00100         switch (paie->owner_type) {
00101                 case UID_ACE:
00102                         DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
00103                         return (uint32)paie->unix_ug.uid;
00104                 case GID_ACE:
00105                         DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
00106                         return (uint32)paie->unix_ug.gid;
00107                 case WORLD_ACE:
00108                 default:
00109                         DEBUG(10,("get_pai_entry_val: world ace\n"));
00110                         return (uint32)-1;
00111         }
00112 }
00113 
00114 /************************************************************************
00115  Return a uint32 of the entry principal.
00116 ************************************************************************/
00117 
00118 static uint32 get_entry_val(canon_ace *ace_entry)
00119 {
00120         switch (ace_entry->owner_type) {
00121                 case UID_ACE:
00122                         DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
00123                         return (uint32)ace_entry->unix_ug.uid;
00124                 case GID_ACE:
00125                         DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
00126                         return (uint32)ace_entry->unix_ug.gid;
00127                 case WORLD_ACE:
00128                 default:
00129                         DEBUG(10,("get_entry_val: world ace\n"));
00130                         return (uint32)-1;
00131         }
00132 }
00133 
00134 /************************************************************************
00135  Count the inherited entries.
00136 ************************************************************************/
00137 
00138 static unsigned int num_inherited_entries(canon_ace *ace_list)
00139 {
00140         unsigned int num_entries = 0;
00141 
00142         for (; ace_list; ace_list = ace_list->next)
00143                 if (ace_list->inherited)
00144                         num_entries++;
00145         return num_entries;
00146 }
00147 
00148 /************************************************************************
00149  Create the on-disk format. Caller must free.
00150 ************************************************************************/
00151 
00152 static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL pai_protected, size_t *store_size)
00153 {
00154         char *pai_buf = NULL;
00155         canon_ace *ace_list = NULL;
00156         char *entry_offset = NULL;
00157         unsigned int num_entries = 0;
00158         unsigned int num_def_entries = 0;
00159 
00160         for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next)
00161                 if (ace_list->inherited)
00162                         num_entries++;
00163 
00164         for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next)
00165                 if (ace_list->inherited)
00166                         num_def_entries++;
00167 
00168         DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries ));
00169 
00170         *store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH);
00171 
00172         pai_buf = (char *)SMB_MALLOC(*store_size);
00173         if (!pai_buf) {
00174                 return NULL;
00175         }
00176 
00177         /* Set up the header. */
00178         memset(pai_buf, '\0', PAI_ENTRIES_BASE);
00179         SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION);
00180         SCVAL(pai_buf,PAI_FLAG_OFFSET,(pai_protected ? PAI_ACL_FLAG_PROTECTED : 0));
00181         SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries);
00182         SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
00183 
00184         entry_offset = pai_buf + PAI_ENTRIES_BASE;
00185 
00186         for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
00187                 if (ace_list->inherited) {
00188                         uint8 type_val = (unsigned char)ace_list->owner_type;
00189                         uint32 entry_val = get_entry_val(ace_list);
00190 
00191                         SCVAL(entry_offset,0,type_val);
00192                         SIVAL(entry_offset,1,entry_val);
00193                         entry_offset += PAI_ENTRY_LENGTH;
00194                 }
00195         }
00196 
00197         for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
00198                 if (ace_list->inherited) {
00199                         uint8 type_val = (unsigned char)ace_list->owner_type;
00200                         uint32 entry_val = get_entry_val(ace_list);
00201 
00202                         SCVAL(entry_offset,0,type_val);
00203                         SIVAL(entry_offset,1,entry_val);
00204                         entry_offset += PAI_ENTRY_LENGTH;
00205                 }
00206         }
00207 
00208         return pai_buf;
00209 }
00210 
00211 /************************************************************************
00212  Store the user.SAMBA_PAI attribute on disk.
00213 ************************************************************************/
00214 
00215 static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list,
00216                                         canon_ace *dir_ace_list, BOOL pai_protected)
00217 {
00218         int ret;
00219         size_t store_size;
00220         char *pai_buf;
00221 
00222         if (!lp_map_acl_inherit(SNUM(fsp->conn)))
00223                 return;
00224 
00225         /*
00226          * Don't store if this ACL isn't protected and
00227          * none of the entries in it are marked as inherited.
00228          */
00229 
00230         if (!pai_protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) {
00231                 /* Instead just remove the attribute if it exists. */
00232                 if (fsp->fh->fd != -1)
00233                         SMB_VFS_FREMOVEXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME);
00234                 else
00235                         SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME);
00236                 return;
00237         }
00238 
00239         pai_buf = create_pai_buf(file_ace_list, dir_ace_list, pai_protected, &store_size);
00240 
00241         if (fsp->fh->fd != -1)
00242                 ret = SMB_VFS_FSETXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
00243                                 pai_buf, store_size, 0);
00244         else
00245                 ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME,
00246                                 pai_buf, store_size, 0);
00247 
00248         SAFE_FREE(pai_buf);
00249 
00250         DEBUG(10,("store_inheritance_attribute:%s for file %s\n", pai_protected ? " (protected)" : "", fsp->fsp_name));
00251         if (ret == -1 && !no_acl_syscall_error(errno))
00252                 DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
00253 }
00254 
00255 /************************************************************************
00256  Delete the in memory inheritance info.
00257 ************************************************************************/
00258 
00259 static void free_inherited_info(struct pai_val *pal)
00260 {
00261         if (pal) {
00262                 struct pai_entry *paie, *paie_next;
00263                 for (paie = pal->entry_list; paie; paie = paie_next) {
00264                         paie_next = paie->next;
00265                         SAFE_FREE(paie);
00266                 }
00267                 for (paie = pal->def_entry_list; paie; paie = paie_next) {
00268                         paie_next = paie->next;
00269                         SAFE_FREE(paie);
00270                 }
00271                 SAFE_FREE(pal);
00272         }
00273 }
00274 
00275 /************************************************************************
00276  Was this ACL protected ?
00277 ************************************************************************/
00278 
00279 static BOOL get_protected_flag(struct pai_val *pal)
00280 {
00281         if (!pal)
00282                 return False;
00283         return pal->pai_protected;
00284 }
00285 
00286 /************************************************************************
00287  Was this ACE inherited ?
00288 ************************************************************************/
00289 
00290 static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace)
00291 {
00292         struct pai_entry *paie;
00293 
00294         if (!pal)
00295                 return False;
00296 
00297         /* If the entry exists it is inherited. */
00298         for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) {
00299                 if (ace_entry->owner_type == paie->owner_type &&
00300                                 get_entry_val(ace_entry) == get_pai_entry_val(paie))
00301                         return True;
00302         }
00303         return False;
00304 }
00305 
00306 /************************************************************************
00307  Ensure an attribute just read is valid.
00308 ************************************************************************/
00309 
00310 static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size)
00311 {
00312         uint16 num_entries;
00313         uint16 num_def_entries;
00314 
00315         if (pai_buf_data_size < PAI_ENTRIES_BASE) {
00316                 /* Corrupted - too small. */
00317                 return False;
00318         }
00319 
00320         if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION)
00321                 return False;
00322 
00323         num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET);
00324         num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
00325 
00326         /* Check the entry lists match. */
00327         /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
00328 
00329         if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size)
00330                 return False;
00331 
00332         return True;
00333 }
00334 
00335 
00336 /************************************************************************
00337  Convert to in-memory format.
00338 ************************************************************************/
00339 
00340 static struct pai_val *create_pai_val(char *buf, size_t size)
00341 {
00342         char *entry_offset;
00343         struct pai_val *paiv = NULL;
00344         int i;
00345 
00346         if (!check_pai_ok(buf, size))
00347                 return NULL;
00348 
00349         paiv = SMB_MALLOC_P(struct pai_val);
00350         if (!paiv)
00351                 return NULL;
00352 
00353         memset(paiv, '\0', sizeof(struct pai_val));
00354 
00355         paiv->pai_protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED);
00356 
00357         paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET);
00358         paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
00359 
00360         entry_offset = buf + PAI_ENTRIES_BASE;
00361 
00362         DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n",
00363                         paiv->pai_protected ? " (pai_protected)" : "", paiv->num_entries, paiv->num_def_entries ));
00364 
00365         for (i = 0; i < paiv->num_entries; i++) {
00366                 struct pai_entry *paie;
00367 
00368                 paie = SMB_MALLOC_P(struct pai_entry);
00369                 if (!paie) {
00370                         free_inherited_info(paiv);
00371                         return NULL;
00372                 }
00373 
00374                 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
00375                 switch( paie->owner_type) {
00376                         case UID_ACE:
00377                                 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
00378                                 DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
00379                                 break;
00380                         case GID_ACE:
00381                                 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
00382                                 DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
00383                                 break;
00384                         case WORLD_ACE:
00385                                 paie->unix_ug.world = -1;
00386                                 DEBUG(10,("create_pai_val: world ace\n"));
00387                                 break;
00388                         default:
00389                                 free_inherited_info(paiv);
00390                                 return NULL;
00391                 }
00392                 entry_offset += PAI_ENTRY_LENGTH;
00393                 DLIST_ADD(paiv->entry_list, paie);
00394         }
00395 
00396         for (i = 0; i < paiv->num_def_entries; i++) {
00397                 struct pai_entry *paie;
00398 
00399                 paie = SMB_MALLOC_P(struct pai_entry);
00400                 if (!paie) {
00401                         free_inherited_info(paiv);
00402                         return NULL;
00403                 }
00404 
00405                 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
00406                 switch( paie->owner_type) {
00407                         case UID_ACE:
00408                                 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
00409                                 DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid ));
00410                                 break;
00411                         case GID_ACE:
00412                                 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
00413                                 DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid ));
00414                                 break;
00415                         case WORLD_ACE:
00416                                 paie->unix_ug.world = -1;
00417                                 DEBUG(10,("create_pai_val: (def) world ace\n"));
00418                                 break;
00419                         default:
00420                                 free_inherited_info(paiv);
00421                                 return NULL;
00422                 }
00423                 entry_offset += PAI_ENTRY_LENGTH;
00424                 DLIST_ADD(paiv->def_entry_list, paie);
00425         }
00426 
00427         return paiv;
00428 }
00429 
00430 /************************************************************************
00431  Load the user.SAMBA_PAI attribute.
00432 ************************************************************************/
00433 
00434 static struct pai_val *load_inherited_info(files_struct *fsp)
00435 {
00436         char *pai_buf;
00437         size_t pai_buf_size = 1024;
00438         struct pai_val *paiv = NULL;
00439         ssize_t ret;
00440 
00441         if (!lp_map_acl_inherit(SNUM(fsp->conn)))
00442                 return NULL;
00443 
00444         if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
00445                 return NULL;
00446 
00447         do {
00448                 if (fsp->fh->fd != -1)
00449                         ret = SMB_VFS_FGETXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
00450                                         pai_buf, pai_buf_size);
00451                 else
00452                         ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME,
00453                                         pai_buf, pai_buf_size);
00454 
00455                 if (ret == -1) {
00456                         if (errno != ERANGE) {
00457                                 break;
00458                         }
00459                         /* Buffer too small - enlarge it. */
00460                         pai_buf_size *= 2;
00461                         SAFE_FREE(pai_buf);
00462                         if (pai_buf_size > 1024*1024) {
00463                                 return NULL; /* Limit malloc to 1mb. */
00464                         }
00465                         if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
00466                                 return NULL;
00467                 }
00468         } while (ret == -1);
00469 
00470         DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name));
00471 
00472         if (ret == -1) {
00473                 /* No attribute or not supported. */
00474 #if defined(ENOATTR)
00475                 if (errno != ENOATTR)
00476                         DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
00477 #else
00478                 if (errno != ENOSYS)
00479                         DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
00480 #endif
00481                 SAFE_FREE(pai_buf);
00482                 return NULL;
00483         }
00484 
00485         paiv = create_pai_val(pai_buf, ret);
00486 
00487         if (paiv && paiv->pai_protected)
00488                 DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name));
00489 
00490         SAFE_FREE(pai_buf);
00491         return paiv;
00492 }
00493 
00494 /****************************************************************************
00495  Functions to manipulate the internal ACE format.
00496 ****************************************************************************/
00497 
00498 /****************************************************************************
00499  Count a linked list of canonical ACE entries.
00500 ****************************************************************************/
00501 
00502 static size_t count_canon_ace_list( canon_ace *list_head )
00503 {
00504         size_t count = 0;
00505         canon_ace *ace;
00506 
00507         for (ace = list_head; ace; ace = ace->next)
00508                 count++;
00509 
00510         return count;
00511 }
00512 
00513 /****************************************************************************
00514  Free a linked list of canonical ACE entries.
00515 ****************************************************************************/
00516 
00517 static void free_canon_ace_list( canon_ace *list_head )
00518 {
00519         canon_ace *list, *next;
00520 
00521         for (list = list_head; list; list = next) {
00522                 next = list->next;
00523                 DLIST_REMOVE(list_head, list);
00524                 SAFE_FREE(list);
00525         }
00526 }
00527 
00528 /****************************************************************************
00529  Function to duplicate a canon_ace entry.
00530 ****************************************************************************/
00531 
00532 static canon_ace *dup_canon_ace( canon_ace *src_ace)
00533 {
00534         canon_ace *dst_ace = SMB_MALLOC_P(canon_ace);
00535 
00536         if (dst_ace == NULL)
00537                 return NULL;
00538 
00539         *dst_ace = *src_ace;
00540         dst_ace->prev = dst_ace->next = NULL;
00541         return dst_ace;
00542 }
00543 
00544 /****************************************************************************
00545  Print out a canon ace.
00546 ****************************************************************************/
00547 
00548 static void print_canon_ace(canon_ace *pace, int num)
00549 {
00550         fstring str;
00551 
00552         dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
00553         dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
00554         if (pace->owner_type == UID_ACE) {
00555                 const char *u_name = uidtoname(pace->unix_ug.uid);
00556                 dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name );
00557         } else if (pace->owner_type == GID_ACE) {
00558                 char *g_name = gidtoname(pace->unix_ug.gid);
00559                 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name );
00560         } else
00561                 dbgtext( "other ");
00562         switch (pace->type) {
00563                 case SMB_ACL_USER:
00564                         dbgtext( "SMB_ACL_USER ");
00565                         break;
00566                 case SMB_ACL_USER_OBJ:
00567                         dbgtext( "SMB_ACL_USER_OBJ ");
00568                         break;
00569                 case SMB_ACL_GROUP:
00570                         dbgtext( "SMB_ACL_GROUP ");
00571                         break;
00572                 case SMB_ACL_GROUP_OBJ:
00573                         dbgtext( "SMB_ACL_GROUP_OBJ ");
00574                         break;
00575                 case SMB_ACL_OTHER:
00576                         dbgtext( "SMB_ACL_OTHER ");
00577                         break;
00578                 default:
00579                         dbgtext( "MASK " );
00580                         break;
00581         }
00582         if (pace->inherited)
00583                 dbgtext( "(inherited) ");
00584         dbgtext( "perms ");
00585         dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
00586         dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
00587         dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
00588 }
00589 
00590 /****************************************************************************
00591  Print out a canon ace list.
00592 ****************************************************************************/
00593 
00594 static void print_canon_ace_list(const char *name, canon_ace *ace_list)
00595 {
00596         int count = 0;
00597 
00598         if( DEBUGLVL( 10 )) {
00599                 dbgtext( "print_canon_ace_list: %s\n", name );
00600                 for (;ace_list; ace_list = ace_list->next, count++)
00601                         print_canon_ace(ace_list, count );
00602         }
00603 }
00604 
00605 /****************************************************************************
00606  Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
00607 ****************************************************************************/
00608 
00609 static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
00610 {
00611         mode_t ret = 0;
00612 
00613         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
00614         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
00615         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
00616 
00617         return ret;
00618 }
00619 
00620 /****************************************************************************
00621  Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
00622 ****************************************************************************/
00623 
00624 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
00625 {
00626         mode_t ret = 0;
00627 
00628         if (mode & r_mask)
00629                 ret |= S_IRUSR;
00630         if (mode & w_mask)
00631                 ret |= S_IWUSR;
00632         if (mode & x_mask)
00633                 ret |= S_IXUSR;
00634 
00635         return ret;
00636 }
00637 
00638 /****************************************************************************
00639  Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
00640  an SMB_ACL_PERMSET_T.
00641 ****************************************************************************/
00642 
00643 static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
00644 {
00645         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1)
00646                 return -1;
00647         if (mode & S_IRUSR) {
00648                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
00649                         return -1;
00650         }
00651         if (mode & S_IWUSR) {
00652                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
00653                         return -1;
00654         }
00655         if (mode & S_IXUSR) {
00656                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
00657                         return -1;
00658         }
00659         return 0;
00660 }
00661 
00662 /****************************************************************************
00663  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
00664 ****************************************************************************/
00665 
00666 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
00667 {
00668         uid_to_sid( powner_sid, psbuf->st_uid );
00669         gid_to_sid( pgroup_sid, psbuf->st_gid );
00670 }
00671 
00672 /****************************************************************************
00673  Is the identity in two ACEs equal ? Check both SID and uid/gid.
00674 ****************************************************************************/
00675 
00676 static BOOL identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
00677 {
00678         if (sid_equal(&ace1->trustee, &ace2->trustee)) {
00679                 return True;
00680         }
00681         if (ace1->owner_type == ace2->owner_type) {
00682                 if (ace1->owner_type == UID_ACE &&
00683                                 ace1->unix_ug.uid == ace2->unix_ug.uid) {
00684                         return True;
00685                 } else if (ace1->owner_type == GID_ACE &&
00686                                 ace1->unix_ug.gid == ace2->unix_ug.gid) {
00687                         return True;
00688                 }
00689         }
00690         return False;
00691 }
00692 
00693 /****************************************************************************
00694  Merge aces with a common sid - if both are allow or deny, OR the permissions together and
00695  delete the second one. If the first is deny, mask the permissions off and delete the allow
00696  if the permissions become zero, delete the deny if the permissions are non zero.
00697 ****************************************************************************/
00698 
00699 static void merge_aces( canon_ace **pp_list_head )
00700 {
00701         canon_ace *list_head = *pp_list_head;
00702         canon_ace *curr_ace_outer;
00703         canon_ace *curr_ace_outer_next;
00704 
00705         /*
00706          * First, merge allow entries with identical SIDs, and deny entries
00707          * with identical SIDs.
00708          */
00709 
00710         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
00711                 canon_ace *curr_ace;
00712                 canon_ace *curr_ace_next;
00713 
00714                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
00715 
00716                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
00717 
00718                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
00719 
00720                         if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
00721                                 (curr_ace->attr == curr_ace_outer->attr)) {
00722 
00723                                 if( DEBUGLVL( 10 )) {
00724                                         dbgtext("merge_aces: Merging ACE's\n");
00725                                         print_canon_ace( curr_ace_outer, 0);
00726                                         print_canon_ace( curr_ace, 0);
00727                                 }
00728 
00729                                 /* Merge two allow or two deny ACE's. */
00730 
00731                                 curr_ace_outer->perms |= curr_ace->perms;
00732                                 DLIST_REMOVE(list_head, curr_ace);
00733                                 SAFE_FREE(curr_ace);
00734                                 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
00735                         }
00736                 }
00737         }
00738 
00739         /*
00740          * Now go through and mask off allow permissions with deny permissions.
00741          * We can delete either the allow or deny here as we know that each SID
00742          * appears only once in the list.
00743          */
00744 
00745         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
00746                 canon_ace *curr_ace;
00747                 canon_ace *curr_ace_next;
00748 
00749                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
00750 
00751                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
00752 
00753                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
00754 
00755                         /*
00756                          * Subtract ACE's with different entries. Due to the ordering constraints
00757                          * we've put on the ACL, we know the deny must be the first one.
00758                          */
00759 
00760                         if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
00761                                 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
00762 
00763                                 if( DEBUGLVL( 10 )) {
00764                                         dbgtext("merge_aces: Masking ACE's\n");
00765                                         print_canon_ace( curr_ace_outer, 0);
00766                                         print_canon_ace( curr_ace, 0);
00767                                 }
00768 
00769                                 curr_ace->perms &= ~curr_ace_outer->perms;
00770 
00771                                 if (curr_ace->perms == 0) {
00772 
00773                                         /*
00774                                          * The deny overrides the allow. Remove the allow.
00775                                          */
00776 
00777                                         DLIST_REMOVE(list_head, curr_ace);
00778                                         SAFE_FREE(curr_ace);
00779                                         curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
00780 
00781                                 } else {
00782 
00783                                         /*
00784                                          * Even after removing permissions, there
00785                                          * are still allow permissions - delete the deny.
00786                                          * It is safe to delete the deny here,
00787                                          * as we are guarenteed by the deny first
00788                                          * ordering that all the deny entries for
00789                                          * this SID have already been merged into one
00790                                          * before we can get to an allow ace.
00791                                          */
00792 
00793                                         DLIST_REMOVE(list_head, curr_ace_outer);
00794                                         SAFE_FREE(curr_ace_outer);
00795                                         break;
00796                                 }
00797                         }
00798 
00799                 } /* end for curr_ace */
00800         } /* end for curr_ace_outer */
00801 
00802         /* We may have modified the list. */
00803 
00804         *pp_list_head = list_head;
00805 }
00806 
00807 /****************************************************************************
00808  Check if we need to return NT4.x compatible ACL entries.
00809 ****************************************************************************/
00810 
00811 static BOOL nt4_compatible_acls(void)
00812 {
00813         int compat = lp_acl_compatibility();
00814 
00815         if (compat == ACL_COMPAT_AUTO) {
00816                 enum remote_arch_types ra_type = get_remote_arch();
00817 
00818                 /* Automatically adapt to client */
00819                 return (ra_type <= RA_WINNT);
00820         } else
00821                 return (compat == ACL_COMPAT_WINNT);
00822 }
00823 
00824 
00825 /****************************************************************************
00826  Map canon_ace perms to permission bits NT.
00827  The attr element is not used here - we only process deny entries on set,
00828  not get. Deny entries are implicit on get with ace->perms = 0.
00829 ****************************************************************************/
00830 
00831 static SEC_ACCESS map_canon_ace_perms(int snum,
00832                                 int *pacl_type,
00833                                 mode_t perms,
00834                                 BOOL directory_ace)
00835 {
00836         SEC_ACCESS sa;
00837         uint32 nt_mask = 0;
00838 
00839         *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
00840 
00841         if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) {
00842                 if (directory_ace) {
00843                         nt_mask = UNIX_DIRECTORY_ACCESS_RWX;
00844                 } else {
00845                         nt_mask = UNIX_ACCESS_RWX;
00846                 }
00847         } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) {
00848                 /*
00849                  * Windows NT refuses to display ACEs with no permissions in them (but
00850                  * they are perfectly legal with Windows 2000). If the ACE has empty
00851                  * permissions we cannot use 0, so we use the otherwise unused
00852                  * WRITE_OWNER permission, which we ignore when we set an ACL.
00853                  * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
00854                  * to be changed in the future.
00855                  */
00856 
00857                 if (nt4_compatible_acls())
00858                         nt_mask = UNIX_ACCESS_NONE;
00859                 else
00860                         nt_mask = 0;
00861         } else {
00862                 if (directory_ace) {
00863                         nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
00864                         nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 );
00865                         nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 );
00866                 } else {
00867                         nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
00868                         nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
00869                         nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
00870                 }
00871         }
00872 
00873         DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
00874                         (unsigned int)perms, (unsigned int)nt_mask ));
00875 
00876         init_sec_access(&sa,nt_mask);
00877         return sa;
00878 }
00879 
00880 /****************************************************************************
00881  Map NT perms to a UNIX mode_t.
00882 ****************************************************************************/
00883 
00884 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
00885 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
00886 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
00887 
00888 static mode_t map_nt_perms( uint32 *mask, int type)
00889 {
00890         mode_t mode = 0;
00891 
00892         switch(type) {
00893         case S_IRUSR:
00894                 if((*mask) & GENERIC_ALL_ACCESS)
00895                         mode = S_IRUSR|S_IWUSR|S_IXUSR;
00896                 else {
00897                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
00898                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
00899                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
00900                 }
00901                 break;
00902         case S_IRGRP:
00903                 if((*mask) & GENERIC_ALL_ACCESS)
00904                         mode = S_IRGRP|S_IWGRP|S_IXGRP;
00905                 else {
00906                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
00907                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
00908                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
00909                 }
00910                 break;
00911         case S_IROTH:
00912                 if((*mask) & GENERIC_ALL_ACCESS)
00913                         mode = S_IROTH|S_IWOTH|S_IXOTH;
00914                 else {
00915                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
00916                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
00917                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
00918                 }
00919                 break;
00920         }
00921 
00922         return mode;
00923 }
00924 
00925 /****************************************************************************
00926  Unpack a SEC_DESC into a UNIX owner and group.
00927 ****************************************************************************/
00928 
00929 BOOL unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
00930 {
00931         DOM_SID owner_sid;
00932         DOM_SID grp_sid;
00933 
00934         *puser = (uid_t)-1;
00935         *pgrp = (gid_t)-1;
00936 
00937         if(security_info_sent == 0) {
00938                 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
00939                 return True;
00940         }
00941 
00942         /*
00943          * Validate the owner and group SID's.
00944          */
00945 
00946         memset(&owner_sid, '\0', sizeof(owner_sid));
00947         memset(&grp_sid, '\0', sizeof(grp_sid));
00948 
00949         DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
00950 
00951         /*
00952          * Don't immediately fail if the owner sid cannot be validated.
00953          * This may be a group chown only set.
00954          */
00955 
00956         if (security_info_sent & OWNER_SECURITY_INFORMATION) {
00957                 sid_copy(&owner_sid, psd->owner_sid);
00958                 if (!sid_to_uid(&owner_sid, puser)) {
00959                         if (lp_force_unknown_acl_user(snum)) {
00960                                 /* this allows take ownership to work
00961                                  * reasonably */
00962                                 *puser = current_user.ut.uid;
00963                         } else {
00964                                 DEBUG(3,("unpack_nt_owners: unable to validate"
00965                                          " owner sid for %s\n",
00966                                          sid_string_static(&owner_sid)));
00967                                 return False;
00968                         }
00969                 }
00970         }
00971 
00972         /*
00973          * Don't immediately fail if the group sid cannot be validated.
00974          * This may be an owner chown only set.
00975          */
00976 
00977         if (security_info_sent & GROUP_SECURITY_INFORMATION) {
00978                 sid_copy(&grp_sid, psd->group_sid);
00979                 if (!sid_to_gid( &grp_sid, pgrp)) {
00980                         if (lp_force_unknown_acl_user(snum)) {
00981                                 /* this allows take group ownership to work
00982                                  * reasonably */
00983                                 *pgrp = current_user.ut.gid;
00984                         } else {
00985                                 DEBUG(3,("unpack_nt_owners: unable to validate"
00986                                          " group sid.\n"));
00987                                 return False;
00988                         }
00989                 }
00990         }
00991 
00992         DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
00993 
00994         return True;
00995 }
00996 
00997 /****************************************************************************
00998  Ensure the enforced permissions for this share apply.
00999 ****************************************************************************/
01000 
01001 static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
01002 {
01003         int snum = SNUM(fsp->conn);
01004         mode_t and_bits = (mode_t)0;
01005         mode_t or_bits = (mode_t)0;
01006 
01007         /* Get the initial bits to apply. */
01008 
01009         if (fsp->is_directory) {
01010                 and_bits = lp_dir_security_mask(snum);
01011                 or_bits = lp_force_dir_security_mode(snum);
01012         } else {
01013                 and_bits = lp_security_mask(snum);
01014                 or_bits = lp_force_security_mode(snum);
01015         }
01016 
01017         /* Now bounce them into the S_USR space. */     
01018         switch(type) {
01019         case S_IRUSR:
01020                 /* Ensure owner has read access. */
01021                 pace->perms |= S_IRUSR;
01022                 if (fsp->is_directory)
01023                         pace->perms |= (S_IWUSR|S_IXUSR);
01024                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
01025                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
01026                 break;
01027         case S_IRGRP:
01028                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
01029                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
01030                 break;
01031         case S_IROTH:
01032                 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
01033                 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
01034                 break;
01035         }
01036 
01037         pace->perms = ((pace->perms & and_bits)|or_bits);
01038 }
01039 
01040 /****************************************************************************
01041  Check if a given uid/SID is in a group gid/SID. This is probably very
01042  expensive and will need optimisation. A *lot* of optimisation :-). JRA.
01043 ****************************************************************************/
01044 
01045 static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
01046 {
01047         fstring u_name;
01048 
01049         /* "Everyone" always matches every uid. */
01050 
01051         if (sid_equal(&group_ace->trustee, &global_sid_World))
01052                 return True;
01053 
01054         /* Assume that the current user is in the current group (force group) */
01055 
01056         if (uid_ace->unix_ug.uid == current_user.ut.uid && group_ace->unix_ug.gid == current_user.ut.gid)
01057                 return True;
01058 
01059         fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
01060         return user_in_group_sid(u_name, &group_ace->trustee);
01061 }
01062 
01063 /****************************************************************************
01064  A well formed POSIX file or default ACL has at least 3 entries, a 
01065  SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
01066  In addition, the owner must always have at least read access.
01067  When using this call on get_acl, the pst struct is valid and contains
01068  the mode of the file. When using this call on set_acl, the pst struct has
01069  been modified to have a mode containing the default for this file or directory
01070  type.
01071 ****************************************************************************/
01072 
01073 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
01074                                                         files_struct *fsp,
01075                                                         const DOM_SID *pfile_owner_sid,
01076                                                         const DOM_SID *pfile_grp_sid,
01077                                                         SMB_STRUCT_STAT *pst,
01078                                                         BOOL setting_acl)
01079 {
01080         canon_ace *pace;
01081         BOOL got_user = False;
01082         BOOL got_grp = False;
01083         BOOL got_other = False;
01084         canon_ace *pace_other = NULL;
01085 
01086         for (pace = *pp_ace; pace; pace = pace->next) {
01087                 if (pace->type == SMB_ACL_USER_OBJ) {
01088 
01089                         if (setting_acl)
01090                                 apply_default_perms(fsp, pace, S_IRUSR);
01091                         got_user = True;
01092 
01093                 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
01094 
01095                         /*
01096                          * Ensure create mask/force create mode is respected on set.
01097                          */
01098 
01099                         if (setting_acl)
01100                                 apply_default_perms(fsp, pace, S_IRGRP);
01101                         got_grp = True;
01102 
01103                 } else if (pace->type == SMB_ACL_OTHER) {
01104 
01105                         /*
01106                          * Ensure create mask/force create mode is respected on set.
01107                          */
01108 
01109                         if (setting_acl)
01110                                 apply_default_perms(fsp, pace, S_IROTH);
01111                         got_other = True;
01112                         pace_other = pace;
01113                 }
01114         }
01115 
01116         if (!got_user) {
01117                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
01118                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
01119                         return False;
01120                 }
01121 
01122                 ZERO_STRUCTP(pace);
01123                 pace->type = SMB_ACL_USER_OBJ;
01124                 pace->owner_type = UID_ACE;
01125                 pace->unix_ug.uid = pst->st_uid;
01126                 pace->trustee = *pfile_owner_sid;
01127                 pace->attr = ALLOW_ACE;
01128 
01129                 if (setting_acl) {
01130                         /* See if the owning user is in any of the other groups in
01131                            the ACE. If so, OR in the permissions from that group. */
01132 
01133                         BOOL group_matched = False;
01134                         canon_ace *pace_iter;
01135 
01136                         for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
01137                                 if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
01138                                         if (uid_entry_in_group(pace, pace_iter)) {
01139                                                 pace->perms |= pace_iter->perms;
01140                                                 group_matched = True;
01141                                         }
01142                                 }
01143                         }
01144 
01145                         /* If we only got an "everyone" perm, just use that. */
01146                         if (!group_matched) {
01147                                 if (got_other)
01148                                         pace->perms = pace_other->perms;
01149                                 else
01150                                         pace->perms = 0;
01151                         }
01152 
01153                         apply_default_perms(fsp, pace, S_IRUSR);
01154                 } else {
01155                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
01156                 }
01157 
01158                 DLIST_ADD(*pp_ace, pace);
01159         }
01160 
01161         if (!got_grp) {
01162                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
01163                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
01164                         return False;
01165                 }
01166 
01167                 ZERO_STRUCTP(pace);
01168                 pace->type = SMB_ACL_GROUP_OBJ;
01169                 pace->owner_type = GID_ACE;
01170                 pace->unix_ug.uid = pst->st_gid;
01171                 pace->trustee = *pfile_grp_sid;
01172                 pace->attr = ALLOW_ACE;
01173                 if (setting_acl) {
01174                         /* If we only got an "everyone" perm, just use that. */
01175                         if (got_other)
01176                                 pace->perms = pace_other->perms;
01177                         else
01178                                 pace->perms = 0;
01179                         apply_default_perms(fsp, pace, S_IRGRP);
01180                 } else {
01181                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
01182                 }
01183 
01184                 DLIST_ADD(*pp_ace, pace);
01185         }
01186 
01187         if (!got_other) {
01188                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
01189                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
01190                         return False;
01191                 }
01192 
01193                 ZERO_STRUCTP(pace);
01194                 pace->type = SMB_ACL_OTHER;
01195                 pace->owner_type = WORLD_ACE;
01196                 pace->unix_ug.world = -1;
01197                 pace->trustee = global_sid_World;
01198                 pace->attr = ALLOW_ACE;
01199                 if (setting_acl) {
01200                         pace->perms = 0;
01201                         apply_default_perms(fsp, pace, S_IROTH);
01202                 } else
01203                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
01204 
01205                 DLIST_ADD(*pp_ace, pace);
01206         }
01207 
01208         return True;
01209 }
01210 
01211 /****************************************************************************
01212  Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
01213  If it does not have them, check if there are any entries where the trustee is the
01214  file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
01215 ****************************************************************************/
01216 
01217 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
01218 {
01219         BOOL got_user_obj, got_group_obj;
01220         canon_ace *current_ace;
01221         int i, entries;
01222 
01223         entries = count_canon_ace_list(ace);
01224         got_user_obj = False;
01225         got_group_obj = False;
01226 
01227         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
01228                 if (current_ace->type == SMB_ACL_USER_OBJ)
01229                         got_user_obj = True;
01230                 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
01231                         got_group_obj = True;
01232         }
01233         if (got_user_obj && got_group_obj) {
01234                 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
01235                 return;
01236         }
01237 
01238         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
01239                 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
01240                                 sid_equal(&current_ace->trustee, pfile_owner_sid)) {
01241                         current_ace->type = SMB_ACL_USER_OBJ;
01242                         got_user_obj = True;
01243                 }
01244                 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
01245                                 sid_equal(&current_ace->trustee, pfile_grp_sid)) {
01246                         current_ace->type = SMB_ACL_GROUP_OBJ;
01247                         got_group_obj = True;
01248                 }
01249         }
01250         if (!got_user_obj)
01251                 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
01252         if (!got_group_obj)
01253                 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
01254 }
01255 
01256 /****************************************************************************
01257  Unpack a SEC_DESC into two canonical ace lists.
01258 ****************************************************************************/
01259 
01260 static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
01261                                                         DOM_SID *pfile_owner_sid,
01262                                                         DOM_SID *pfile_grp_sid,
01263                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
01264                                                         SEC_ACL *dacl)
01265 {
01266         BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
01267         canon_ace *file_ace = NULL;
01268         canon_ace *dir_ace = NULL;
01269         canon_ace *current_ace = NULL;
01270         BOOL got_dir_allow = False;
01271         BOOL got_file_allow = False;
01272         int i, j;
01273 
01274         *ppfile_ace = NULL;
01275         *ppdir_ace = NULL;
01276 
01277         /*
01278          * Convert the incoming ACL into a more regular form.
01279          */
01280 
01281         for(i = 0; i < dacl->num_aces; i++) {
01282                 SEC_ACE *psa = &dacl->aces[i];
01283 
01284                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
01285                         DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
01286                         return False;
01287                 }
01288 
01289                 if (nt4_compatible_acls()) {
01290                         /*
01291                          * The security mask may be UNIX_ACCESS_NONE which should map into
01292                          * no permissions (we overload the WRITE_OWNER bit for this) or it
01293                          * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
01294                          * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
01295                          */
01296 
01297                         /*
01298                          * Convert GENERIC bits to specific bits.
01299                          */
01300  
01301                         se_map_generic(&psa->access_mask, &file_generic_mapping);
01302 
01303                         psa->access_mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
01304 
01305                         if(psa->access_mask != UNIX_ACCESS_NONE)
01306                                 psa->access_mask &= ~UNIX_ACCESS_NONE;
01307                 }
01308         }
01309 
01310         /*
01311          * Deal with the fact that NT 4.x re-writes the canonical format
01312          * that we return for default ACLs. If a directory ACE is identical
01313          * to a inherited directory ACE then NT changes the bits so that the
01314          * first ACE is set to OI|IO and the second ACE for this SID is set
01315          * to CI. We need to repair this. JRA.
01316          */
01317 
01318         for(i = 0; i < dacl->num_aces; i++) {
01319                 SEC_ACE *psa1 = &dacl->aces[i];
01320 
01321                 for (j = i + 1; j < dacl->num_aces; j++) {
01322                         SEC_ACE *psa2 = &dacl->aces[j];
01323 
01324                         if (psa1->access_mask != psa2->access_mask)
01325                                 continue;
01326 
01327                         if (!sid_equal(&psa1->trustee, &psa2->trustee))
01328                                 continue;
01329 
01330                         /*
01331                          * Ok - permission bits and SIDs are equal.
01332                          * Check if flags were re-written.
01333                          */
01334 
01335                         if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
01336 
01337                                 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
01338                                 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
01339 
01340                         } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
01341 
01342                                 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
01343                                 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
01344 
01345                         }
01346                 }
01347         }
01348 
01349         for(i = 0; i < dacl->num_aces; i++) {
01350                 SEC_ACE *psa = &dacl->aces[i];
01351 
01352                 /*
01353                  * Create a cannon_ace entry representing this NT DACL ACE.
01354                  */
01355 
01356                 if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
01357                         free_canon_ace_list(file_ace);
01358                         free_canon_ace_list(dir_ace);
01359                         DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
01360                         return False;
01361                 }
01362 
01363                 ZERO_STRUCTP(current_ace);
01364 
01365                 sid_copy(&current_ace->trustee, &psa->trustee);
01366 
01367                 /*
01368                  * Try and work out if the SID is a user or group
01369                  * as we need to flag these differently for POSIX.
01370                  * Note what kind of a POSIX ACL this should map to.
01371                  */
01372 
01373                 if( sid_equal(&current_ace->trustee, &global_sid_World)) {
01374                         current_ace->owner_type = WORLD_ACE;
01375                         current_ace->unix_ug.world = -1;
01376                         current_ace->type = SMB_ACL_OTHER;
01377                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
01378                         current_ace->owner_type = UID_ACE;
01379                         current_ace->unix_ug.uid = pst->st_uid;
01380                         current_ace->type = SMB_ACL_USER_OBJ;
01381 
01382                         /*
01383                          * The Creator Owner entry only specifies inheritable permissions,
01384                          * never access permissions. WinNT doesn't always set the ACE to
01385                          *INHERIT_ONLY, though.
01386                          */
01387 
01388                         if (nt4_compatible_acls())
01389                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
01390                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
01391                         current_ace->owner_type = GID_ACE;
01392                         current_ace->unix_ug.gid = pst->st_gid;
01393                         current_ace->type = SMB_ACL_GROUP_OBJ;
01394 
01395                         /*
01396                          * The Creator Group entry only specifies inheritable permissions,
01397                          * never access permissions. WinNT doesn't always set the ACE to
01398                          *INHERIT_ONLY, though.
01399                          */
01400                         if (nt4_compatible_acls())
01401                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
01402 
01403                 } else if (sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid)) {
01404                         current_ace->owner_type = UID_ACE;
01405                         /* If it's the owning user, this is a user_obj, not
01406                          * a user. */
01407                         if (current_ace->unix_ug.uid == pst->st_uid) {
01408                                 current_ace->type = SMB_ACL_USER_OBJ;
01409                         } else {
01410                                 current_ace->type = SMB_ACL_USER;
01411                         }
01412                 } else if (sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid)) {
01413                         current_ace->owner_type = GID_ACE;
01414                         /* If it's the primary group, this is a group_obj, not
01415                          * a group. */
01416                         if (current_ace->unix_ug.gid == pst->st_gid) {
01417                                 current_ace->type = SMB_ACL_GROUP_OBJ;
01418                         } else {
01419                                 current_ace->type = SMB_ACL_GROUP;
01420                         }
01421                 } else {
01422                         fstring str;
01423 
01424                         /*
01425                          * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
01426                          */
01427 
01428                         if (non_mappable_sid(&psa->trustee)) {
01429                                 DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
01430                                         sid_to_string(str, &psa->trustee) ));
01431                                 SAFE_FREE(current_ace);
01432                                 continue;
01433                         }
01434 
01435                         free_canon_ace_list(file_ace);
01436                         free_canon_ace_list(dir_ace);
01437                         DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
01438                                 sid_to_string(str, &current_ace->trustee) ));
01439                         SAFE_FREE(current_ace);
01440                         return False;
01441                 }
01442 
01443                 /*
01444                  * Map the given NT permissions into a UNIX mode_t containing only
01445                  * S_I(R|W|X)USR bits.
01446                  */
01447 
01448                 current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
01449                 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
01450                 current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
01451 
01452                 /*
01453                  * Now add the created ace to either the file list, the directory
01454                  * list, or both. We *MUST* preserve the order here (hence we use
01455                  * DLIST_ADD_END) as NT ACLs are order dependent.
01456                  */
01457 
01458                 if (fsp->is_directory) {
01459 
01460                         /*
01461                          * We can only add to the default POSIX ACE list if the ACE is
01462                          * designed to be inherited by both files and directories.
01463                          */
01464 
01465                         if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
01466                                 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
01467 
01468                                 DLIST_ADD_END(dir_ace, current_ace, canon_ace *);
01469 
01470                                 /*
01471                                  * Note if this was an allow ace. We can't process
01472                                  * any further deny ace's after this.
01473                                  */
01474 
01475                                 if (current_ace->attr == ALLOW_ACE)
01476                                         got_dir_allow = True;
01477 
01478                                 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
01479                                         DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
01480 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
01481                                         free_canon_ace_list(file_ace);
01482                                         free_canon_ace_list(dir_ace);
01483                                         return False;
01484                                 }       
01485 
01486                                 if( DEBUGLVL( 10 )) {
01487                                         dbgtext("create_canon_ace_lists: adding dir ACL:\n");
01488                                         print_canon_ace( current_ace, 0);
01489                                 }
01490 
01491                                 /*
01492                                  * If this is not an inherit only ACE we need to add a duplicate
01493                                  * to the file acl.
01494                                  */
01495 
01496                                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
01497                                         canon_ace *dup_ace = dup_canon_ace(current_ace);
01498 
01499                                         if (!dup_ace) {
01500                                                 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
01501                                                 free_canon_ace_list(file_ace);
01502                                                 free_canon_ace_list(dir_ace);
01503                                                 return False;
01504                                         }
01505 
01506                                         /*
01507                                          * We must not free current_ace here as its
01508                                          * pointer is now owned by the dir_ace list.
01509                                          */
01510                                         current_ace = dup_ace;
01511                                 } else {
01512                                         /*
01513                                          * We must not free current_ace here as its
01514                                          * pointer is now owned by the dir_ace list.
01515                                          */
01516                                         current_ace = NULL;
01517                                 }
01518                         }
01519                 }
01520 
01521                 /*
01522                  * Only add to the file ACL if not inherit only.
01523                  */
01524 
01525                 if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
01526                         DLIST_ADD_END(file_ace, current_ace, canon_ace *);
01527 
01528                         /*
01529                          * Note if this was an allow ace. We can't process
01530                          * any further deny ace's after this.
01531                          */
01532 
01533                         if (current_ace->attr == ALLOW_ACE)
01534                                 got_file_allow = True;
01535 
01536                         if ((current_ace->attr == DENY_ACE) && got_file_allow) {
01537                                 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
01538 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
01539                                 free_canon_ace_list(file_ace);
01540                                 free_canon_ace_list(dir_ace);
01541                                 return False;
01542                         }       
01543 
01544                         if( DEBUGLVL( 10 )) {
01545                                 dbgtext("create_canon_ace_lists: adding file ACL:\n");
01546                                 print_canon_ace( current_ace, 0);
01547                         }
01548                         all_aces_are_inherit_only = False;
01549                         /*
01550                          * We must not free current_ace here as its
01551                          * pointer is now owned by the file_ace list.
01552                          */
01553                         current_ace = NULL;
01554                 }
01555 
01556                 /*
01557                  * Free if ACE was not added.
01558                  */
01559 
01560                 SAFE_FREE(current_ace);
01561         }
01562 
01563         if (fsp->is_directory && all_aces_are_inherit_only) {
01564                 /*
01565                  * Windows 2000 is doing one of these weird 'inherit acl'
01566                  * traverses to conserve NTFS ACL resources. Just pretend
01567                  * there was no DACL sent. JRA.
01568                  */
01569 
01570                 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
01571                 free_canon_ace_list(file_ace);
01572                 free_canon_ace_list(dir_ace);
01573                 file_ace = NULL;
01574                 dir_ace = NULL;
01575         } else {
01576                 /*
01577                  * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
01578                  * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
01579                  * entries can be converted to *_OBJ. Usually we will already have these
01580                  * entries in the Default ACL, and the Access ACL will not have them.
01581                  */
01582                 if (file_ace) {
01583                         check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
01584                 }
01585                 if (dir_ace) {
01586                         check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
01587                 }
01588         }
01589 
01590         *ppfile_ace = file_ace;
01591         *ppdir_ace = dir_ace;
01592 
01593         return True;
01594 }
01595 
01596 /****************************************************************************
01597  ASCII art time again... JRA :-).
01598 
01599  We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
01600  we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
01601  entries). Secondly, the merge code has ensured that all duplicate SID entries for
01602  allow or deny have been merged, so the same SID can only appear once in the deny
01603  list or once in the allow list.
01604 
01605  We then process as follows :
01606 
01607  ---------------------------------------------------------------------------
01608  First pass - look for a Everyone DENY entry.
01609 
01610  If it is deny all (rwx) trunate the list at this point.
01611  Else, walk the list from this point and use the deny permissions of this
01612  entry as a mask on all following allow entries. Finally, delete
01613  the Everyone DENY entry (we have applied it to everything possible).
01614 
01615  In addition, in this pass we remove any DENY entries that have 
01616  no permissions (ie. they are a DENY nothing).
01617  ---------------------------------------------------------------------------
01618  Second pass - only deal with deny user entries.
01619 
01620  DENY user1 (perms XXX)
01621 
01622  new_perms = 0
01623  for all following allow group entries where user1 is in group
01624         new_perms |= group_perms;
01625 
01626  user1 entry perms = new_perms & ~ XXX;
01627 
01628  Convert the deny entry to an allow entry with the new perms and
01629  push to the end of the list. Note if the user was in no groups
01630  this maps to a specific allow nothing entry for this user.
01631 
01632  The common case from the NT ACL choser (userX deny all) is
01633  optimised so we don't do the group lookup - we just map to
01634  an allow nothing entry.
01635 
01636  What we're doing here is inferring the allow permissions the
01637  person setting the ACE on user1 wanted by looking at the allow
01638  permissions on the groups the user is currently in. This will
01639  be a snapshot, depending on group membership but is the best
01640  we can do and has the advantage of failing closed rather than
01641  open.
01642  ---------------------------------------------------------------------------
01643  Third pass - only deal with deny group entries.
01644 
01645  DENY group1 (perms XXX)
01646 
01647  for all following allow user entries where user is in group1
01648    user entry perms = user entry perms & ~ XXX;
01649 
01650  If there is a group Everyone allow entry with permissions YYY,
01651  convert the group1 entry to an allow entry and modify its
01652  permissions to be :
01653 
01654  new_perms = YYY & ~ XXX
01655 
01656  and push to the end of the list.
01657 
01658  If there is no group Everyone allow entry then convert the
01659  group1 entry to a allow nothing entry and push to the end of the list.
01660 
01661  Note that the common case from the NT ACL choser (groupX deny all)
01662  cannot be optimised here as we need to modify user entries who are
01663  in the group to change them to a deny all also.
01664 
01665  What we're doing here is modifying the allow permissions of
01666  user entries (which are more specific in POSIX ACLs) to mask
01667  out the explicit deny set on the group they are in. This will
01668  be a snapshot depending on current group membership but is the
01669  best we can do and has the advantage of failing closed rather
01670  than open.
01671  ---------------------------------------------------------------------------
01672  Fourth pass - cope with cumulative permissions.
01673 
01674  for all allow user entries, if there exists an allow group entry with
01675  more permissive permissions, and the user is in that group, rewrite the
01676  allow user permissions to contain both sets of permissions.
01677 
01678  Currently the code for this is #ifdef'ed out as these semantics make
01679  no sense to me. JRA.
01680  ---------------------------------------------------------------------------
01681 
01682  Note we *MUST* do the deny user pass first as this will convert deny user
01683  entries into allow user entries which can then be processed by the deny
01684  group pass.
01685 
01686  The above algorithm took a *lot* of thinking about - hence this
01687  explaination :-). JRA.
01688 ****************************************************************************/
01689 
01690 /****************************************************************************
01691  Process a canon_ace list entries. This is very complex code. We need
01692  to go through and remove the "deny" permissions from any allow entry that matches
01693  the id of this entry. We have already refused any NT ACL that wasn't in correct
01694  order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
01695  we just remove it (to fail safe). We have already removed any duplicate ace
01696  entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
01697  allow entries.
01698 ****************************************************************************/
01699 
01700 static void process_deny_list( canon_ace **pp_ace_list )
01701 {
01702         canon_ace *ace_list = *pp_ace_list;
01703         canon_ace *curr_ace = NULL;
01704         canon_ace *curr_ace_next = NULL;
01705 
01706         /* Pass 1 above - look for an Everyone, deny entry. */
01707 
01708         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
01709                 canon_ace *allow_ace_p;
01710 
01711                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
01712 
01713                 if (curr_ace->attr != DENY_ACE)
01714                         continue;
01715 
01716                 if (curr_ace->perms == (mode_t)0) {
01717 
01718                         /* Deny nothing entry - delete. */
01719 
01720                         DLIST_REMOVE(ace_list, curr_ace);
01721                         continue;
01722                 }
01723 
01724                 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
01725                         continue;
01726 
01727                 /* JRATEST - assert. */
01728                 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
01729 
01730                 if (curr_ace->perms == ALL_ACE_PERMS) {
01731 
01732                         /*
01733                          * Optimisation. This is a DENY_ALL to Everyone. Truncate the
01734                          * list at this point including this entry.
01735                          */
01736 
01737                         canon_ace *prev_entry = curr_ace->prev;
01738 
01739                         free_canon_ace_list( curr_ace );
01740                         if (prev_entry)
01741                                 prev_entry->next = NULL;
01742                         else {
01743                                 /* We deleted the entire list. */
01744                                 ace_list = NULL;
01745                         }
01746                         break;
01747                 }
01748 
01749                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
01750 
01751                         /* 
01752                          * Only mask off allow entries.
01753                          */
01754 
01755                         if (allow_ace_p->attr != ALLOW_ACE)
01756                                 continue;
01757 
01758                         allow_ace_p->perms &= ~curr_ace->perms;
01759                 }
01760 
01761                 /*
01762                  * Now it's been applied, remove it.
01763                  */
01764 
01765                 DLIST_REMOVE(ace_list, curr_ace);
01766         }
01767 
01768         /* Pass 2 above - deal with deny user entries. */
01769 
01770         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
01771                 mode_t new_perms = (mode_t)0;
01772                 canon_ace *allow_ace_p;
01773 
01774                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
01775 
01776                 if (curr_ace->attr != DENY_ACE)
01777                         continue;
01778 
01779                 if (curr_ace->owner_type != UID_ACE)
01780                         continue;
01781 
01782                 if (curr_ace->perms == ALL_ACE_PERMS) {
01783 
01784                         /*
01785                          * Optimisation - this is a deny everything to this user.
01786                          * Convert to an allow nothing and push to the end of the list.
01787                          */
01788 
01789                         curr_ace->attr = ALLOW_ACE;
01790                         curr_ace->perms = (mode_t)0;
01791                         DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
01792                         continue;
01793                 }
01794 
01795                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
01796 
01797                         if (allow_ace_p->attr != ALLOW_ACE)
01798                                 continue;
01799 
01800                         /* We process GID_ACE and WORLD_ACE entries only. */
01801 
01802                         if (allow_ace_p->owner_type == UID_ACE)
01803                                 continue;
01804 
01805                         if (uid_entry_in_group( curr_ace, allow_ace_p))
01806                                 new_perms |= allow_ace_p->perms;
01807                 }
01808 
01809                 /*
01810                  * Convert to a allow entry, modify the perms and push to the end
01811                  * of the list.
01812                  */
01813 
01814                 curr_ace->attr = ALLOW_ACE;
01815                 curr_ace->perms = (new_perms & ~curr_ace->perms);
01816                 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
01817         }
01818 
01819         /* Pass 3 above - deal with deny group entries. */
01820 
01821         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
01822                 canon_ace *allow_ace_p;
01823                 canon_ace *allow_everyone_p = NULL;
01824 
01825                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
01826 
01827                 if (curr_ace->attr != DENY_ACE)
01828                         continue;
01829 
01830                 if (curr_ace->owner_type != GID_ACE)
01831                         continue;
01832 
01833                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
01834 
01835                         if (allow_ace_p->attr != ALLOW_ACE)
01836                                 continue;
01837 
01838                         /* Store a pointer to the Everyone allow, if it exists. */
01839                         if (allow_ace_p->owner_type == WORLD_ACE)
01840                                 allow_everyone_p = allow_ace_p;
01841 
01842                         /* We process UID_ACE entries only. */
01843 
01844                         if (allow_ace_p->owner_type != UID_ACE)
01845                                 continue;
01846 
01847                         /* Mask off the deny group perms. */
01848 
01849                         if (uid_entry_in_group( allow_ace_p, curr_ace))
01850                                 allow_ace_p->perms &= ~curr_ace->perms;
01851                 }
01852 
01853                 /*
01854                  * Convert the deny to an allow with the correct perms and
01855                  * push to the end of the list.
01856                  */
01857 
01858                 curr_ace->attr = ALLOW_ACE;
01859                 if (allow_everyone_p)
01860                         curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
01861                 else
01862                         curr_ace->perms = (mode_t)0;
01863                 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
01864         }
01865 
01866         /* Doing this fourth pass allows Windows semantics to be layered
01867          * on top of POSIX semantics. I'm not sure if this is desirable.
01868          * For example, in W2K ACLs there is no way to say, "Group X no
01869          * access, user Y full access" if user Y is a member of group X.
01870          * This seems completely broken semantics to me.... JRA.
01871          */
01872 
01873 #if 0
01874         /* Pass 4 above - deal with allow entries. */
01875 
01876         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
01877                 canon_ace *allow_ace_p;
01878 
01879                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
01880 
01881                 if (curr_ace->attr != ALLOW_ACE)
01882                         continue;
01883 
01884                 if (curr_ace->owner_type != UID_ACE)
01885                         continue;
01886 
01887                 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
01888 
01889                         if (allow_ace_p->attr != ALLOW_ACE)
01890                                 continue;
01891 
01892                         /* We process GID_ACE entries only. */
01893 
01894                         if (allow_ace_p->owner_type != GID_ACE)
01895                                 continue;
01896 
01897                         /* OR in the group perms. */
01898 
01899                         if (uid_entry_in_group( curr_ace, allow_ace_p))
01900                                 curr_ace->perms |= allow_ace_p->perms;
01901                 }
01902         }
01903 #endif
01904 
01905         *pp_ace_list = ace_list;
01906 }
01907 
01908 /****************************************************************************
01909  Create a default mode that will be used if a security descriptor entry has
01910  no user/group/world entries.
01911 ****************************************************************************/
01912 
01913 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
01914 {
01915         int snum = SNUM(fsp->conn);
01916         mode_t and_bits = (mode_t)0;
01917         mode_t or_bits = (mode_t)0;
01918         mode_t mode = interitable_mode
01919                 ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name,
01920                              NULL )
01921                 : S_IRUSR;
01922 
01923         if (fsp->is_directory)
01924                 mode |= (S_IWUSR|S_IXUSR);
01925 
01926         /*
01927          * Now AND with the create mode/directory mode bits then OR with the
01928          * force create mode/force directory mode bits.
01929          */
01930 
01931         if (fsp->is_directory) {
01932                 and_bits = lp_dir_security_mask(snum);
01933                 or_bits = lp_force_dir_security_mode(snum);
01934         } else {
01935                 and_bits = lp_security_mask(snum);
01936                 or_bits = lp_force_security_mode(snum);
01937         }
01938 
01939         return ((mode & and_bits)|or_bits);
01940 }
01941 
01942 /****************************************************************************
01943  Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
01944  succeeding.
01945 ****************************************************************************/
01946 
01947 static BOOL unpack_canon_ace(files_struct *fsp, 
01948                                                         SMB_STRUCT_STAT *pst,
01949                                                         DOM_SID *pfile_owner_sid,
01950                                                         DOM_SID *pfile_grp_sid,
01951                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
01952                                                         uint32 security_info_sent, SEC_DESC *psd)
01953 {
01954         canon_ace *file_ace = NULL;
01955         canon_ace *dir_ace = NULL;
01956 
01957         *ppfile_ace = NULL;
01958         *ppdir_ace = NULL;
01959 
01960         if(security_info_sent == 0) {
01961                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
01962                 return False;
01963         }
01964 
01965         /*
01966          * If no DACL then this is a chown only security descriptor.
01967          */
01968 
01969         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
01970                 return True;
01971 
01972         /*
01973          * Now go through the DACL and create the canon_ace lists.
01974          */
01975 
01976         if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
01977                                                                 &file_ace, &dir_ace, psd->dacl))
01978                 return False;
01979 
01980         if ((file_ace == NULL) && (dir_ace == NULL)) {
01981                 /* W2K traverse DACL set - ignore. */
01982                 return True;
01983         }
01984 
01985         /*
01986          * Go through the canon_ace list and merge entries
01987          * belonging to identical users of identical allow or deny type.
01988          * We can do this as all deny entries come first, followed by
01989          * all allow entries (we have mandated this before accepting this acl).
01990          */
01991 
01992         print_canon_ace_list( "file ace - before merge", file_ace);
01993         merge_aces( &file_ace );
01994 
01995         print_canon_ace_list( "dir ace - before merge", dir_ace);
01996         merge_aces( &dir_ace );
01997 
01998         /*
01999          * NT ACLs are order dependent. Go through the acl lists and
02000          * process DENY entries by masking the allow entries.
02001          */
02002 
02003         print_canon_ace_list( "file ace - before deny", file_ace);
02004         process_deny_list( &file_ace);
02005 
02006         print_canon_ace_list( "dir ace - before deny", dir_ace);
02007         process_deny_list( &dir_ace);
02008 
02009         /*
02010          * A well formed POSIX file or default ACL has at least 3 entries, a 
02011          * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
02012          * and optionally a mask entry. Ensure this is the case.
02013          */
02014 
02015         print_canon_ace_list( "file ace - before valid", file_ace);
02016 
02017         /*
02018          * A default 3 element mode entry for a file should be r-- --- ---.
02019          * A default 3 element mode entry for a directory should be rwx --- ---.
02020          */
02021 
02022         pst->st_mode = create_default_mode(fsp, False);
02023 
02024         if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
02025                 free_canon_ace_list(file_ace);
02026                 free_canon_ace_list(dir_ace);
02027                 return False;
02028         }
02029 
02030         print_canon_ace_list( "dir ace - before valid", dir_ace);
02031 
02032         /*
02033          * A default inheritable 3 element mode entry for a directory should be the
02034          * mode Samba will use to create a file within. Ensure user rwx bits are set if
02035          * it's a directory.
02036          */
02037 
02038         pst->st_mode = create_default_mode(fsp, True);
02039 
02040         if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
02041                 free_canon_ace_list(file_ace);
02042                 free_canon_ace_list(dir_ace);
02043                 return False;
02044         }
02045 
02046         print_canon_ace_list( "file ace - return", file_ace);
02047         print_canon_ace_list( "dir ace - return", dir_ace);
02048 
02049         *ppfile_ace = file_ace;
02050         *ppdir_ace = dir_ace;
02051         return True;
02052 
02053 }
02054 
02055 /******************************************************************************
02056  When returning permissions, try and fit NT display
02057  semantics if possible. Note the the canon_entries here must have been malloced.
02058  The list format should be - first entry = owner, followed by group and other user
02059  entries, last entry = other.
02060 
02061  Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
02062  are not ordered, and match on the most specific entry rather than walking a list,
02063  then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
02064 
02065  Entry 0: owner : deny all except read and write.
02066  Entry 1: owner : allow read and write.
02067  Entry 2: group : deny all except read.
02068  Entry 3: group : allow read.
02069  Entry 4: Everyone : allow read.
02070 
02071  But NT cannot display this in their ACL editor !
02072 ********************************************************************************/
02073 
02074 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
02075 {
02076         canon_ace *list_head = *pp_list_head;
02077         canon_ace *owner_ace = NULL;
02078         canon_ace *other_ace = NULL;
02079         canon_ace *ace = NULL;
02080 
02081         for (ace = list_head; ace; ace = ace->next) {
02082                 if (ace->type == SMB_ACL_USER_OBJ)
02083                         owner_ace = ace;
02084                 else if (ace->type == SMB_ACL_OTHER) {
02085                         /* Last ace - this is "other" */
02086                         other_ace = ace;
02087                 }
02088         }
02089                 
02090         if (!owner_ace || !other_ace) {
02091                 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
02092                         filename ));
02093                 return;
02094         }
02095 
02096         /*
02097          * The POSIX algorithm applies to owner first, and other last,
02098          * so ensure they are arranged in this order.
02099          */
02100 
02101         if (owner_ace) {
02102                 DLIST_PROMOTE(list_head, owner_ace);
02103         }
02104 
02105         if (other_ace) {
02106                 DLIST_DEMOTE(list_head, other_ace, canon_ace *);
02107         }
02108 
02109         /* We have probably changed the head of the list. */
02110 
02111         *pp_list_head = list_head;
02112 }
02113                 
02114 /****************************************************************************
02115  Create a linked list of canonical ACE entries.
02116 ****************************************************************************/
02117 
02118 static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
02119                                         const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
02120 {
02121         connection_struct *conn = fsp->conn;
02122         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
02123         canon_ace *list_head = NULL;
02124         canon_ace *ace = NULL;
02125         canon_ace *next_ace = NULL;
02126         int entry_id = SMB_ACL_FIRST_ENTRY;
02127         SMB_ACL_ENTRY_T entry;
02128         size_t ace_count;
02129 
02130         while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
02131                 SMB_ACL_TAG_T tagtype;
02132                 SMB_ACL_PERMSET_T permset;
02133                 DOM_SID sid;
02134                 posix_id unix_ug;
02135                 enum ace_owner owner_type;
02136 
02137                 /* get_next... */
02138                 if (entry_id == SMB_ACL_FIRST_ENTRY)
02139                         entry_id = SMB_ACL_NEXT_ENTRY;
02140 
02141                 /* Is this a MASK entry ? */
02142                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
02143                         continue;
02144 
02145                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
02146                         continue;
02147 
02148                 /* Decide which SID to use based on the ACL type. */
02149                 switch(tagtype) {
02150                         case SMB_ACL_USER_OBJ:
02151                                 /* Get the SID from the owner. */
02152                                 sid_copy(&sid, powner);
02153                                 unix_ug.uid = psbuf->st_uid;
02154                                 owner_type = UID_ACE;
02155                                 break;
02156                         case SMB_ACL_USER:
02157                                 {
02158                                         uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
02159                                         if (puid == NULL) {
02160                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
02161                                                 continue;
02162                                         }
02163                                         /*
02164                                          * A SMB_ACL_USER entry for the owner is shadowed by the
02165                                          * SMB_ACL_USER_OBJ entry and Windows also cannot represent
02166                                          * that entry, so we ignore it. We also don't create such
02167                                          * entries out of the blue when setting ACLs, so a get/set
02168                                          * cycle will drop them.
02169                                          */
02170                                         if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) {
02171                                                 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
02172                                                 continue;
02173                                         }
02174                                         uid_to_sid( &sid, *puid);
02175                                         unix_ug.uid = *puid;
02176                                         owner_type = UID_ACE;
02177                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
02178                                         break;
02179                                 }
02180                         case SMB_ACL_GROUP_OBJ:
02181                                 /* Get the SID from the owning group. */
02182                                 sid_copy(&sid, pgroup);
02183                                 unix_ug.gid = psbuf->st_gid;
02184                                 owner_type = GID_ACE;
02185                                 break;
02186                         case SMB_ACL_GROUP:
02187                                 {
02188                                         gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
02189                                         if (pgid == NULL) {
02190                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
02191                                                 continue;
02192                                         }
02193                                         gid_to_sid( &sid, *pgid);
02194                                         unix_ug.gid = *pgid;
02195                                         owner_type = GID_ACE;
02196                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
02197                                         break;
02198                                 }
02199                         case SMB_ACL_MASK:
02200                                 acl_mask = convert_permset_to_mode_t(conn, permset);
02201                                 continue; /* Don't count the mask as an entry. */
02202                         case SMB_ACL_OTHER:
02203                                 /* Use the Everyone SID */
02204                                 sid = global_sid_World;
02205                                 unix_ug.world = -1;
02206                                 owner_type = WORLD_ACE;
02207                                 break;
02208                         default:
02209                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
02210                                 continue;
02211                 }
02212 
02213                 /*
02214                  * Add this entry to the list.
02215                  */
02216 
02217                 if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
02218                         goto fail;
02219 
02220                 ZERO_STRUCTP(ace);
02221                 ace->type = tagtype;
02222                 ace->perms = convert_permset_to_mode_t(conn, permset);
02223                 ace->attr = ALLOW_ACE;
02224                 ace->trustee = sid;
02225                 ace->unix_ug = unix_ug;
02226                 ace->owner_type = owner_type;
02227                 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
02228 
02229                 DLIST_ADD(list_head, ace);
02230         }
02231 
02232         /*
02233          * This next call will ensure we have at least a user/group/world set.
02234          */
02235 
02236         if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
02237                 goto fail;
02238 
02239         /*
02240          * Now go through the list, masking the permissions with the
02241          * acl_mask. Ensure all DENY Entries are at the start of the list.
02242          */
02243 
02244         DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
02245 
02246         for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
02247                 next_ace = ace->next;
02248 
02249                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
02250                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
02251                         ace->perms &= acl_mask;
02252 
02253                 if (ace->perms == 0) {
02254                         DLIST_PROMOTE(list_head, ace);
02255                 }
02256 
02257                 if( DEBUGLVL( 10 ) ) {
02258                         print_canon_ace(ace, ace_count);
02259                 }
02260         }
02261 
02262         arrange_posix_perms(fsp->fsp_name,&list_head );
02263 
02264         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
02265 
02266         return list_head;
02267 
02268   fail:
02269 
02270         free_canon_ace_list(list_head);
02271         return NULL;
02272 }
02273 
02274 /****************************************************************************
02275  Check if the current user group list contains a given group.
02276 ****************************************************************************/
02277 
02278 static BOOL current_user_in_group(gid_t gid)
02279 {
02280         int i;
02281 
02282         for (i = 0; i < current_user.ut.ngroups; i++) {
02283                 if (current_user.ut.groups[i] == gid) {
02284                         return True;
02285                 }
02286         }
02287 
02288         return False;
02289 }
02290 
02291 /****************************************************************************
02292  Should we override a deny ?  Check 'acl group control' and 'dos filemode'
02293 ****************************************************************************/
02294 
02295 static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid, const char *fname)
02296 {
02297         SMB_STRUCT_STAT sbuf;
02298 
02299         if ((errno != EPERM) && (errno != EACCES)) {
02300                 return False;
02301         }
02302 
02303         /* file primary group == user primary or supplementary group */
02304         if (lp_acl_group_control(SNUM(conn)) && current_user_in_group(prim_gid)) {
02305                 return True;
02306         }
02307 
02308         /* user has writeable permission */
02309         if (lp_dos_filemode(SNUM(conn)) && can_write_to_file(conn, fname, &sbuf)) {
02310                 return True;
02311         }
02312 
02313         return False;
02314 }
02315 
02316 /****************************************************************************
02317  Attempt to apply an ACL to a file or directory.
02318 ****************************************************************************/
02319 
02320 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, gid_t prim_gid, BOOL *pacl_set_support)
02321 {
02322         connection_struct *conn = fsp->conn;
02323         BOOL ret = False;
02324         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
02325         canon_ace *p_ace;
02326         int i;
02327         SMB_ACL_ENTRY_T mask_entry;
02328         BOOL got_mask_entry = False;
02329         SMB_ACL_PERMSET_T mask_permset;
02330         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
02331         BOOL needs_mask = False;
02332         mode_t mask_perms = 0;
02333 
02334 #if defined(POSIX_ACL_NEEDS_MASK)
02335         /* HP-UX always wants to have a mask (called "class" there). */
02336         needs_mask = True;
02337 #endif
02338 
02339         if (the_acl == NULL) {
02340 
02341                 if (!no_acl_syscall_error(errno)) {
02342                         /*
02343                          * Only print this error message if we have some kind of ACL
02344                          * support that's not working. Otherwise we would always get this.
02345                          */
02346                         DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
02347                                 default_ace ? "default" : "file", strerror(errno) ));
02348                 }
02349                 *pacl_set_support = False;
02350                 return False;
02351         }
02352 
02353         if( DEBUGLVL( 10 )) {
02354                 dbgtext("set_canon_ace_list: setting ACL:\n");
02355                 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
02356                         print_canon_ace( p_ace, i);
02357                 }
02358         }
02359 
02360         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
02361                 SMB_ACL_ENTRY_T the_entry;
02362                 SMB_ACL_PERMSET_T the_permset;
02363 
02364                 /*
02365                  * ACLs only "need" an ACL_MASK entry if there are any named user or
02366                  * named group entries. But if there is an ACL_MASK entry, it applies
02367                  * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
02368                  * so that it doesn't deny (i.e., mask off) any permissions.
02369                  */
02370 
02371                 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
02372                         needs_mask = True;
02373                         mask_perms |= p_ace->perms;
02374                 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
02375                         mask_perms |= p_ace->perms;
02376                 }
02377 
02378                 /*
02379                  * Get the entry for this ACE.
02380                  */
02381 
02382                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
02383                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
02384                                 i, strerror(errno) ));
02385                         goto fail;
02386                 }
02387 
02388                 if (p_ace->type == SMB_ACL_MASK) {
02389                         mask_entry = the_entry;
02390                         got_mask_entry = True;
02391                 }
02392 
02393                 /*
02394                  * Ok - we now know the ACL calls should be working, don't
02395                  * allow fallback to chmod.
02396                  */
02397 
02398                 *pacl_set_support = True;
02399 
02400                 /*
02401                  * Initialise the entry from the canon_ace.
02402                  */
02403 
02404                 /*
02405                  * First tell the entry what type of ACE this is.
02406                  */
02407 
02408                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
02409                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
02410                                 i, strerror(errno) ));
02411                         goto fail;
02412                 }
02413 
02414                 /*
02415                  * Only set the qualifier (user or group id) if the entry is a user
02416                  * or group id ACE.
02417                  */
02418 
02419                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
02420                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
02421                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
02422                                         i, strerror(errno) ));
02423                                 goto fail;
02424                         }
02425                 }
02426 
02427                 /*
02428                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
02429                  */
02430 
02431                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
02432                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
02433                                 i, strerror(errno) ));
02434                         goto fail;
02435                 }
02436 
02437                 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
02438                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
02439                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
02440                         goto fail;
02441                 }
02442 
02443                 /*
02444                  * ..and apply them to the entry.
02445                  */
02446 
02447                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
02448                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
02449                                 i, strerror(errno) ));
02450                         goto fail;
02451                 }
02452 
02453                 if( DEBUGLVL( 10 ))
02454                         print_canon_ace( p_ace, i);
02455 
02456         }
02457 
02458         if (needs_mask && !got_mask_entry) {
02459                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
02460                         DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
02461                         goto fail;
02462                 }
02463 
02464                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
02465                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
02466                         goto fail;
02467                 }
02468 
02469                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
02470                         DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
02471                         goto fail;
02472                 }
02473 
02474                 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
02475                         DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
02476                         goto fail;
02477                 }
02478 
02479                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
02480                         DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
02481                         goto fail;
02482                 }
02483         }
02484 
02485         /*
02486          * Finally apply it to the file or directory.
02487          */
02488 
02489         if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
02490                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
02491                         /*
02492                          * Some systems allow all the above calls and only fail with no ACL support
02493                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
02494                          */
02495                         if (no_acl_syscall_error(errno)) {
02496                                 *pacl_set_support = False;
02497                         }
02498 
02499                         if (acl_group_override(conn, prim_gid, fsp->fsp_name)) {
02500                                 int sret;
02501 
02502                                 DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
02503                                         fsp->fsp_name ));
02504 
02505                                 become_root();
02506                                 sret = SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl);
02507                                 unbecome_root();
02508                                 if (sret == 0) {
02509                                         ret = True;     
02510                                 }
02511                         }
02512 
02513                         if (ret == False) {
02514                                 DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
02515                                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
02516                                                 fsp->fsp_name, strerror(errno) ));
02517                                 goto fail;
02518                         }
02519                 }
02520         } else {
02521                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl) == -1) {
02522                         /*
02523                          * Some systems allow all the above calls and only fail with no ACL support
02524                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
02525                          */
02526                         if (no_acl_syscall_error(errno)) {
02527                                 *pacl_set_support = False;
02528                         }
02529 
02530                         if (acl_group_override(conn, prim_gid, fsp->fsp_name)) {
02531                                 int sret;
02532 
02533                                 DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
02534                                         fsp->fsp_name ));
02535 
02536                                 become_root();
02537                                 sret = SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl);
02538                                 unbecome_root();
02539                                 if (sret == 0) {
02540                                         ret = True;
02541                                 }
02542                         }
02543 
02544                         if (ret == False) {
02545                                 DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
02546                                                 fsp->fsp_name, strerror(errno) ));
02547                                 goto fail;
02548                         }
02549                 }
02550         }
02551 
02552         ret = True;
02553 
02554   fail:
02555 
02556         if (the_acl != NULL) {
02557                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
02558         }
02559 
02560         return ret;
02561 }
02562 
02563 /****************************************************************************
02564  Find a particular canon_ace entry.
02565 ****************************************************************************/
02566 
02567 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
02568 {
02569         while (list) {
02570                 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
02571                                 (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
02572                                 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
02573                         break;
02574                 list = list->next;
02575         }
02576         return list;
02577 }
02578 
02579 /****************************************************************************
02580  
02581 ****************************************************************************/
02582 
02583 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
02584 {
02585         SMB_ACL_ENTRY_T entry;
02586 
02587         if (!the_acl)
02588                 return NULL;
02589         if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
02590                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
02591                 return NULL;
02592         }
02593         return the_acl;
02594 }
02595 
02596 /****************************************************************************
02597  Convert a canon_ace to a generic 3 element permission - if possible.
02598 ****************************************************************************/
02599 
02600 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
02601 
02602 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
02603 {
02604         int snum = SNUM(fsp->conn);
02605         size_t ace_count = count_canon_ace_list(file_ace_list);
02606         canon_ace *ace_p;
02607         canon_ace *owner_ace = NULL;
02608         canon_ace *group_ace = NULL;
02609         canon_ace *other_ace = NULL;
02610         mode_t and_bits;
02611         mode_t or_bits;
02612 
02613         if (ace_count != 3) {
02614                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
02615 posix perms.\n", fsp->fsp_name ));
02616                 return False;
02617         }
02618 
02619         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
02620                 if (ace_p->owner_type == UID_ACE)
02621                         owner_ace = ace_p;
02622                 else if (ace_p->owner_type == GID_ACE)
02623                         group_ace = ace_p;
02624                 else if (ace_p->owner_type == WORLD_ACE)
02625                         other_ace = ace_p;
02626         }
02627 
02628         if (!owner_ace || !group_ace || !other_ace) {
02629                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
02630                                 fsp->fsp_name ));
02631                 return False;
02632         }
02633 
02634         *posix_perms = (mode_t)0;
02635 
02636         *posix_perms |= owner_ace->perms;
02637         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
02638         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
02639         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
02640         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
02641         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
02642         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
02643 
02644         /* The owner must have at least read access. */
02645 
02646         *posix_perms |= S_IRUSR;
02647         if (fsp->is_directory)
02648                 *posix_perms |= (S_IWUSR|S_IXUSR);
02649 
02650         /* If requested apply the masks. */
02651 
02652         /* Get the initial bits to apply. */
02653 
02654         if (fsp->is_directory) {
02655                 and_bits = lp_dir_security_mask(snum);
02656                 or_bits = lp_force_dir_security_mode(snum);
02657         } else {
02658                 and_bits = lp_security_mask(snum);
02659                 or_bits = lp_force_security_mode(snum);
02660         }
02661 
02662         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
02663 
02664         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
02665                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
02666                 fsp->fsp_name ));
02667 
02668         return True;
02669 }
02670 
02671 /****************************************************************************
02672   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
02673   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
02674   with CI|OI set so it is inherited and also applies to the directory.
02675   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
02676 ****************************************************************************/
02677 
02678 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
02679 {
02680         size_t i, j;
02681 
02682         for (i = 0; i < num_aces; i++) {
02683                 for (j = i+1; j < num_aces; j++) {
02684                         uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
02685                         uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
02686                         BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
02687                         BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
02688 
02689                         /* We know the lower number ACE's are file entries. */
02690                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
02691                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
02692                                 (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
02693                                 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
02694                                 (i_inh == j_inh) &&
02695                                 (i_flags_ni == 0) &&
02696                                 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
02697                                                   SEC_ACE_FLAG_CONTAINER_INHERIT|
02698                                                   SEC_ACE_FLAG_INHERIT_ONLY))) {
02699                                 /*
02700                                  * W2K wants to have access allowed zero access ACE's
02701                                  * at the end of the list. If the mask is zero, merge
02702                                  * the non-inherited ACE onto the inherited ACE.
02703                                  */
02704 
02705                                 if (nt_ace_list[i].access_mask == 0) {
02706                                         nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
02707                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
02708                                         if (num_aces - i - 1 > 0)
02709                                                 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
02710                                                                 sizeof(SEC_ACE));
02711 
02712                                         DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
02713                                                 (unsigned int)i, (unsigned int)j ));
02714                                 } else {
02715                                         /*
02716                                          * These are identical except for the flags.
02717                                          * Merge the inherited ACE onto the non-inherited ACE.
02718                                          */
02719 
02720                                         nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
02721                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
02722                                         if (num_aces - j - 1 > 0)
02723                                                 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
02724                                                                 sizeof(SEC_ACE));
02725 
02726                                         DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
02727                                                 (unsigned int)j, (unsigned int)i ));
02728                                 }
02729                                 num_aces--;
02730                                 break;
02731                         }
02732                 }
02733         }
02734 
02735         return num_aces;
02736 }
02737 /****************************************************************************
02738  Reply to query a security descriptor from an fsp. If it succeeds it allocates
02739  the space for the return elements and returns the size needed to return the
02740  security descriptor. This should be the only external function needed for
02741  the UNIX style get ACL.
02742 ****************************************************************************/
02743 
02744 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
02745 {
02746         connection_struct *conn = fsp->conn;
02747         SMB_STRUCT_STAT sbuf;
02748         SEC_ACE *nt_ace_list = NULL;
02749         DOM_SID owner_sid;
02750         DOM_SID group_sid;
02751         size_t sd_size = 0;
02752         SEC_ACL *psa = NULL;
02753         size_t num_acls = 0;
02754         size_t num_def_acls = 0;
02755         size_t num_aces = 0;
02756         SMB_ACL_T posix_acl = NULL;
02757         SMB_ACL_T def_acl = NULL;
02758         canon_ace *file_ace = NULL;
02759         canon_ace *dir_ace = NULL;
02760         size_t num_profile_acls = 0;
02761         struct pai_val *pal = NULL;
02762         SEC_DESC *psd = NULL;
02763 
02764         *ppdesc = NULL;
02765 
02766         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
02767 
02768         if(fsp->is_directory || fsp->fh->fd == -1) {
02769 
02770                 /* Get the stat struct for the owner info. */
02771                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
02772                         return 0;
02773                 }
02774                 /*
02775                  * Get the ACL from the path.
02776                  */
02777 
02778                 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
02779 
02780                 /*
02781                  * If it's a directory get the default POSIX ACL.
02782                  */
02783 
02784                 if(fsp->is_directory) {
02785                         def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
02786                         def_acl = free_empty_sys_acl(conn, def_acl);
02787                 }
02788 
02789         } else {
02790 
02791                 /* Get the stat struct for the owner info. */
02792                 if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) {
02793                         return 0;
02794                 }
02795                 /*
02796                  * Get the ACL from the fd.
02797                  */
02798                 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
02799         }
02800 
02801         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
02802                         posix_acl ? "present" :  "absent",
02803                         def_acl ? "present" :  "absent" ));
02804 
02805         pal = load_inherited_info(fsp);
02806 
02807         /*
02808          * Get the owner, group and world SIDs.
02809          */
02810 
02811         if (lp_profile_acls(SNUM(conn))) {
02812                 /* For WXP SP1 the owner must be administrators. */
02813                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
02814                 sid_copy(&group_sid, &global_sid_Builtin_Users);
02815                 num_profile_acls = 2;
02816         } else {
02817                 create_file_sids(&sbuf, &owner_sid, &group_sid);
02818         }
02819 
02820         if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
02821 
02822                 /*
02823                  * In the optimum case Creator Owner and Creator Group would be used for
02824                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
02825                  * would lead to usability problems under Windows: The Creator entries
02826                  * are only available in browse lists of directories and not for files;
02827                  * additionally the identity of the owning group couldn't be determined.
02828                  * We therefore use those identities only for Default ACLs. 
02829                  */
02830 
02831                 /* Create the canon_ace lists. */
02832                 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
02833 
02834                 /* We must have *some* ACLS. */
02835         
02836                 if (count_canon_ace_list(file_ace) == 0) {
02837                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
02838                         goto done;
02839                 }
02840 
02841                 if (fsp->is_directory && def_acl) {
02842                         dir_ace = canonicalise_acl(fsp, def_acl, &sbuf,
02843                                         &global_sid_Creator_Owner,
02844                                         &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
02845                 }
02846 
02847                 /*
02848                  * Create the NT ACE list from the canonical ace lists.
02849                  */
02850 
02851                 {
02852                         canon_ace *ace;
02853                         int nt_acl_type;
02854                         int i;
02855 
02856                         if (nt4_compatible_acls() && dir_ace) {
02857                                 /*
02858                                  * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
02859                                  * but no non-INHERIT_ONLY entry for one SID. So we only
02860                                  * remove entries from the Access ACL if the
02861                                  * corresponding Default ACL entries have also been
02862                                  * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
02863                                  * are exceptions. We can do nothing
02864                                  * intelligent if the Default ACL contains entries that
02865                                  * are not also contained in the Access ACL, so this
02866                                  * case will still fail under NT 4.
02867                                  */
02868 
02869                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
02870                                 if (ace && !ace->perms) {
02871                                         DLIST_REMOVE(dir_ace, ace);
02872                                         SAFE_FREE(ace);
02873 
02874                                         ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
02875                                         if (ace && !ace->perms) {
02876                                                 DLIST_REMOVE(file_ace, ace);
02877                                                 SAFE_FREE(ace);
02878                                         }
02879                                 }
02880 
02881                                 /*
02882                                  * WinNT doesn't usually have Creator Group
02883                                  * in browse lists, so we send this entry to
02884                                  * WinNT even if it contains no relevant
02885                                  * permissions. Once we can add
02886                                  * Creator Group to browse lists we can
02887                                  * re-enable this.
02888                                  */
02889 
02890 #if 0
02891                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
02892                                 if (ace && !ace->perms) {
02893                                         DLIST_REMOVE(dir_ace, ace);
02894                                         SAFE_FREE(ace);
02895                                 }
02896 #endif
02897 
02898                                 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
02899                                 if (ace && !ace->perms) {
02900                                         DLIST_REMOVE(file_ace, ace);
02901                                         SAFE_FREE(ace);
02902                                 }
02903                         }
02904 
02905                         num_acls = count_canon_ace_list(file_ace);
02906                         num_def_acls = count_canon_ace_list(dir_ace);
02907 
02908                         /* Allocate the ace list. */
02909                         if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
02910                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
02911                                 goto done;
02912                         }
02913 
02914                         memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
02915 
02916                         /*
02917                          * Create the NT ACE list from the canonical ace lists.
02918                          */
02919 
02920                         ace = file_ace;
02921 
02922                         for (i = 0; i < num_acls; i++, ace = ace->next) {
02923                                 SEC_ACCESS acc;
02924 
02925                                 acc = map_canon_ace_perms(SNUM(conn),
02926                                                 &nt_acl_type,
02927                                                 ace->perms,
02928                                                 fsp->is_directory);
02929                                 init_sec_ace(&nt_ace_list[num_aces++],
02930                                         &ace->trustee,
02931                                         nt_acl_type,
02932                                         acc,
02933                                         ace->inherited ?
02934                                                 SEC_ACE_FLAG_INHERITED_ACE : 0);
02935                         }
02936 
02937                         /* The User must have access to a profile share - even
02938                          * if we can't map the SID. */
02939                         if (lp_profile_acls(SNUM(conn))) {
02940                                 SEC_ACCESS acc;
02941 
02942                                 init_sec_access(&acc,FILE_GENERIC_ALL);
02943                                 init_sec_ace(&nt_ace_list[num_aces++],
02944                                                 &global_sid_Builtin_Users,
02945                                                 SEC_ACE_TYPE_ACCESS_ALLOWED,
02946                                                 acc, 0);
02947                         }
02948 
02949                         ace = dir_ace;
02950 
02951                         for (i = 0; i < num_def_acls; i++, ace = ace->next) {
02952                                 SEC_ACCESS acc;
02953 
02954                                 acc = map_canon_ace_perms(SNUM(conn),
02955                                                 &nt_acl_type,
02956                                                 ace->perms,
02957                                                 fsp->is_directory);
02958                                 init_sec_ace(&nt_ace_list[num_aces++],
02959                                         &ace->trustee,
02960                                         nt_acl_type,
02961                                         acc,
02962                                         SEC_ACE_FLAG_OBJECT_INHERIT|
02963                                         SEC_ACE_FLAG_CONTAINER_INHERIT|
02964                                         SEC_ACE_FLAG_INHERIT_ONLY|
02965                                         (ace->inherited ?
02966                                            SEC_ACE_FLAG_INHERITED_ACE : 0));
02967                         }
02968 
02969                         /* The User must have access to a profile share - even
02970                          * if we can't map the SID. */
02971                         if (lp_profile_acls(SNUM(conn))) {
02972                                 SEC_ACCESS acc;
02973 
02974                                 init_sec_access(&acc,FILE_GENERIC_ALL);
02975                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
02976                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
02977                                                 SEC_ACE_FLAG_INHERIT_ONLY|0);
02978                         }
02979 
02980                         /*
02981                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
02982                          * Win2K needs this to get the inheritance correct when replacing ACLs
02983                          * on a directory tree. Based on work by Jim @ IBM.
02984                          */
02985 
02986                         num_aces = merge_default_aces(nt_ace_list, num_aces);
02987 
02988                 }
02989 
02990                 if (num_aces) {
02991                         if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
02992                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
02993                                 goto done;
02994                         }
02995                 }
02996         } /* security_info & DACL_SECURITY_INFORMATION */
02997 
02998         psd = make_standard_sec_desc( main_loop_talloc_get(),
02999                         (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
03000                         (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
03001                         psa,
03002                         &sd_size);
03003 
03004         if(!psd) {
03005                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
03006                 sd_size = 0;
03007                 goto done;
03008         }
03009 
03010         /*
03011          * Windows 2000: The DACL_PROTECTED flag in the security
03012          * descriptor marks the ACL as non-inheriting, i.e., no
03013          * ACEs from higher level directories propagate to this
03014          * ACL. In the POSIX ACL model permissions are only
03015          * inherited at file create time, so ACLs never contain
03016          * any ACEs that are inherited dynamically. The DACL_PROTECTED
03017          * flag doesn't seem to bother Windows NT.
03018          * Always set this if map acl inherit is turned off.
03019          */
03020         if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) {
03021                 psd->type |= SE_DESC_DACL_PROTECTED;
03022         }
03023 
03024         if (psd->dacl) {
03025                 dacl_sort_into_canonical_order(psd->dacl->aces, (unsigned int)psd->dacl->num_aces);
03026         }
03027 
03028         *ppdesc = psd;
03029 
03030  done:
03031 
03032         if (posix_acl) {
03033                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
03034         }
03035         if (def_acl) {
03036                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
03037         }
03038         free_canon_ace_list(file_ace);
03039         free_canon_ace_list(dir_ace);
03040         free_inherited_info(pal);
03041         SAFE_FREE(nt_ace_list);
03042 
03043         return sd_size;
03044 }
03045 
03046 /****************************************************************************
03047  Try to chown a file. We will be able to chown it under the following conditions.
03048 
03049   1) If we have root privileges, then it will just work.
03050   2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
03051   3) If we have SeRestorePrivilege we can change the user to any other user. 
03052   4) If we have write permission to the file and dos_filemodes is set
03053      then allow chown to the currently authenticated user.
03054 ****************************************************************************/
03055 
03056 int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
03057 {
03058         int ret;
03059         files_struct *fsp;
03060         SMB_STRUCT_STAT st;
03061 
03062         if(!CAN_WRITE(conn)) {
03063                 return -1;
03064         }
03065 
03066         /* Case (1). */
03067         /* try the direct way first */
03068         ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
03069         if (ret == 0)
03070                 return 0;
03071 
03072         /* Case (2) / (3) */
03073         if (lp_enable_privileges()) {
03074 
03075                 BOOL has_take_ownership_priv = user_has_privileges(current_user.nt_user_token,
03076                                                               &se_take_ownership);
03077                 BOOL has_restore_priv = user_has_privileges(current_user.nt_user_token,
03078                                                        &se_restore);
03079 
03080                 /* Case (2) */
03081                 if ( ( has_take_ownership_priv && ( uid == current_user.ut.uid ) ) ||
03082                 /* Case (3) */
03083                      ( has_restore_priv ) ) {
03084 
03085                         become_root();
03086                         /* Keep the current file gid the same - take ownership doesn't imply group change. */
03087                         ret = SMB_VFS_CHOWN(conn, fname, uid, (gid_t)-1);
03088                         unbecome_root();
03089                         return ret;
03090                 }
03091         }
03092 
03093         /* Case (4). */
03094         if (!lp_dos_filemode(SNUM(conn))) {
03095                 return -1;
03096         }
03097 
03098         /* only allow chown to the current user. This is more secure,
03099            and also copes with the case where the SID in a take ownership ACL is
03100            a local SID on the users workstation
03101         */
03102         if (uid != current_user.ut.uid) {
03103                 errno = EPERM;
03104                 return -1;
03105         }
03106 
03107         if (SMB_VFS_STAT(conn,fname,&st)) {
03108                 return -1;
03109         }
03110 
03111         if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,&st,&fsp))) {
03112                 return -1;
03113         }
03114 
03115         become_root();
03116         /* Keep the current file gid the same. */
03117         ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, uid, (gid_t)-1);
03118         unbecome_root();
03119 
03120         close_file_fchmod(fsp);
03121 
03122         return ret;
03123 }
03124 
03125 #if 0
03126 /* Disable this - prevents ACL inheritance from the ACL editor. JRA. */
03127 
03128 /****************************************************************************
03129  Take care of parent ACL inheritance.
03130 ****************************************************************************/
03131 
03132 static NTSTATUS append_parent_acl(files_struct *fsp,
03133                                 SMB_STRUCT_STAT *psbuf,
03134                                 SEC_DESC *psd,
03135                                 SEC_DESC **pp_new_sd)
03136 {
03137         SEC_DESC *parent_sd = NULL;
03138         files_struct *parent_fsp = NULL;
03139         TALLOC_CTX *mem_ctx = talloc_parent(psd);
03140         char *parent_name = NULL;
03141         SEC_ACE *new_ace = NULL;
03142         unsigned int num_aces = psd->dacl->num_aces;
03143         SMB_STRUCT_STAT sbuf;
03144         NTSTATUS status;
03145         int info;
03146         size_t sd_size;
03147         unsigned int i, j;
03148         BOOL is_dacl_protected = (psd->type & SE_DESC_DACL_PROTECTED);
03149 
03150         ZERO_STRUCT(sbuf);
03151 
03152         if (mem_ctx == NULL) {
03153                 return NT_STATUS_NO_MEMORY;
03154         }
03155 
03156         if (!parent_dirname_talloc(mem_ctx,
03157                                 fsp->fsp_name,
03158                                 &parent_name,
03159                                 NULL)) {
03160                 return NT_STATUS_NO_MEMORY;
03161         }
03162 
03163         status = open_directory(fsp->conn,
03164                                 parent_name,
03165                                 &sbuf,
03166                                 FILE_READ_ATTRIBUTES, /* Just a stat open */
03167                                 FILE_SHARE_NONE, /* Ignored for stat opens */
03168                                 FILE_OPEN,
03169                                 0,
03170                                 0,
03171                                 &info,
03172                                 &parent_fsp);
03173 
03174         if (!NT_STATUS_IS_OK(status)) {
03175                 return status;
03176         }
03177 
03178         sd_size = SMB_VFS_GET_NT_ACL(parent_fsp, parent_fsp->fsp_name,
03179                         DACL_SECURITY_INFORMATION, &parent_sd );
03180 
03181         close_file(parent_fsp, NORMAL_CLOSE);
03182 
03183         if (!sd_size) {
03184                 return NT_STATUS_ACCESS_DENIED;
03185         }
03186 
03187         /*
03188          * Make room for potentially all the ACLs from
03189          * the parent. We used to add the ugw triple here,
03190          * as we knew we were dealing with POSIX ACLs.
03191          * We no longer need to do so as we can guarentee
03192          * that a default ACL from the parent directory will
03193          * be well formed for POSIX ACLs if it came from a
03194          * POSIX ACL source, and if we're not writing to a
03195          * POSIX ACL sink then we don't care if it's not well
03196          * formed. JRA.
03197          */
03198 
03199         num_aces += parent_sd->dacl->num_aces;
03200 
03201         if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, SEC_ACE,
03202                                         num_aces)) == NULL) {
03203                 return NT_STATUS_NO_MEMORY;
03204         }
03205 
03206         /* Start by copying in all the given ACE entries. */
03207         for (i = 0; i < psd->dacl->num_aces; i++) {
03208                 sec_ace_copy(&new_ace[i], &psd->dacl->aces[i]);
03209         }
03210 
03211         /*
03212          * Note that we're ignoring "inherit permissions" here
03213          * as that really only applies to newly created files. JRA.
03214          */
03215 
03216         /* Finally append any inherited ACEs. */
03217         for (j = 0; j < parent_sd->dacl->num_aces; j++) {
03218                 SEC_ACE *se = &parent_sd->dacl->aces[j];
03219 
03220                 if (fsp->is_directory) {
03221                         if (!(se->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
03222                                 /* Doesn't apply to a directory - ignore. */
03223                                 DEBUG(10,("append_parent_acl: directory %s "
03224                                         "ignoring non container "
03225                                         "inherit flags %u on ACE with sid %s "
03226                                         "from parent %s\n",
03227                                         fsp->fsp_name,
03228                                         (unsigned int)se->flags,
03229                                         sid_string_static(&se->trustee),
03230                                         parent_name));
03231                                 continue;
03232                         }
03233                 } else {
03234                         if (!(se->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
03235                                 /* Doesn't apply to a file - ignore. */
03236                                 DEBUG(10,("append_parent_acl: file %s "
03237                                         "ignoring non object "
03238                                         "inherit flags %u on ACE with sid %s "
03239                                         "from parent %s\n",
03240                                         fsp->fsp_name,
03241                                         (unsigned int)se->flags,
03242                                         sid_string_static(&se->trustee),
03243                                         parent_name));
03244                                 continue;
03245                         }
03246                 }
03247 
03248                 if (is_dacl_protected) {
03249                         /* If the DACL is protected it means we must
03250                          * not overwrite an existing ACE entry with the
03251                          * same SID. This is order N^2. Ouch :-(. JRA. */
03252                         unsigned int k;
03253                         for (k = 0; k < psd->dacl->num_aces; k++) {
03254                                 if (sid_equal(&psd->dacl->aces[k].trustee,
03255                                                 &se->trustee)) {
03256                                         break;
03257                                 }
03258                         }
03259                         if (k < psd->dacl->num_aces) {
03260                                 /* SID matched. Ignore. */
03261                                 DEBUG(10,("append_parent_acl: path %s "
03262                                         "ignoring ACE with protected sid %s "
03263                                         "from parent %s\n",
03264                                         fsp->fsp_name,
03265                                         sid_string_static(&se->trustee),
03266                                         parent_name));
03267                                 continue;
03268                         }
03269                 }
03270 
03271                 sec_ace_copy(&new_ace[i], se);
03272                 if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
03273                         new_ace[i].flags &= ~(SEC_ACE_FLAG_VALID_INHERIT);
03274                 }
03275                 new_ace[i].flags |= SEC_ACE_FLAG_INHERITED_ACE;
03276 
03277                 if (fsp->is_directory) {
03278                         /*
03279                          * Strip off any inherit only. It's applied.
03280                          */
03281                         new_ace[i].flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY);
03282                         if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
03283                                 /* No further inheritance. */
03284                                 new_ace[i].flags &=
03285                                         ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
03286                                         SEC_ACE_FLAG_OBJECT_INHERIT);
03287                         }
03288                 } else {
03289                         /*
03290                          * Strip off any container or inherit
03291                          * flags, they can't apply to objects.
03292                          */
03293                         new_ace[i].flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
03294                                                 SEC_ACE_FLAG_INHERIT_ONLY|
03295                                                 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT);
03296                 }
03297 
03298                 i++;
03299 
03300                 DEBUG(10,("append_parent_acl: path %s "
03301                         "inheriting ACE with sid %s "
03302                         "from parent %s\n",
03303                         fsp->fsp_name,
03304                         sid_string_static(&se->trustee),
03305                         parent_name));
03306 
03307         }
03308 
03309         parent_sd->dacl->aces = new_ace;
03310         parent_sd->dacl->num_aces = i;
03311 
03312         *pp_new_sd = parent_sd;
03313         return status;
03314 }
03315 
03316 #endif
03317 
03318 /****************************************************************************
03319  Reply to set a security descriptor on an fsp. security_info_sent is the
03320  description of the following NT ACL.
03321  This should be the only external function needed for the UNIX style set ACL.
03322 ****************************************************************************/
03323 
03324 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
03325 {
03326         connection_struct *conn = fsp->conn;
03327         uid_t user = (uid_t)-1;
03328         gid_t grp = (gid_t)-1;
03329         SMB_STRUCT_STAT sbuf;
03330         DOM_SID file_owner_sid;
03331         DOM_SID file_grp_sid;
03332         canon_ace *file_ace_list = NULL;
03333         canon_ace *dir_ace_list = NULL;
03334         BOOL acl_perms = False;
03335         mode_t orig_mode = (mode_t)0;
03336         BOOL set_acl_as_root = False;
03337         BOOL acl_set_support = False;
03338         BOOL ret = False;
03339 
03340         DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
03341 
03342         if (!CAN_WRITE(conn)) {
03343                 DEBUG(10,("set acl rejected on read-only share\n"));
03344                 return False;
03345         }
03346 
03347         /*
03348          * Get the current state of the file.
03349          */
03350 
03351         if(fsp->is_directory || fsp->fh->fd == -1) {
03352                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
03353                         return False;
03354         } else {
03355                 if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0)
03356                         return False;
03357         }
03358 
03359         /* Save the original element we check against. */
03360         orig_mode = sbuf.st_mode;
03361 
03362         /*
03363          * Unpack the user/group/world id's.
03364          */
03365 
03366         if (!unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd)) {
03367                 return False;
03368         }
03369 
03370         /*
03371          * Do we need to chown ?
03372          */
03373 
03374         if (((user != (uid_t)-1) && (sbuf.st_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_gid != grp))) {
03375 
03376                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
03377                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
03378 
03379                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
03380                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
03381                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
03382                         return False;
03383                 }
03384 
03385                 /*
03386                  * Recheck the current state of the file, which may have changed.
03387                  * (suid/sgid bits, for instance)
03388                  */
03389 
03390                 if(fsp->is_directory) {
03391                         if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
03392                                 return False;
03393                         }
03394                 } else {
03395 
03396                         int sret;
03397 
03398                         if(fsp->fh->fd == -1)
03399                                 sret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
03400                         else
03401                                 sret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf);
03402 
03403                         if(sret != 0)
03404                                 return False;
03405                 }
03406 
03407                 /* Save the original element we check against. */
03408                 orig_mode = sbuf.st_mode;
03409 
03410                 /* If we successfully chowned, we know we must
03411                  * be able to set the acl, so do it as root.
03412                  */
03413                 set_acl_as_root = True;
03414         }
03415 
03416         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
03417 
03418         acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
03419                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
03420 
03421         /* Ignore W2K traverse DACL set. */
03422         if (!file_ace_list && !dir_ace_list) {
03423                 return True;
03424         }
03425  
03426         if (!acl_perms) {
03427                 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
03428                 free_canon_ace_list(file_ace_list);
03429                 free_canon_ace_list(dir_ace_list);
03430                 return False;
03431         }
03432  
03433         /*
03434          * Only change security if we got a DACL.
03435          */
03436  
03437         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || (psd->dacl == NULL)) {
03438                 free_canon_ace_list(file_ace_list);
03439                 free_canon_ace_list(dir_ace_list);
03440                 return True;
03441         }
03442  
03443         /*
03444          * Try using the POSIX ACL set first. Fall back to chmod if
03445          * we have no ACL support on this filesystem.
03446          */
03447  
03448         if (acl_perms && file_ace_list) {
03449                 if (set_acl_as_root) {
03450                         become_root();
03451                 }
03452                 ret = set_canon_ace_list(fsp, file_ace_list, False, sbuf.st_gid, &acl_set_support);
03453                 if (set_acl_as_root) {
03454                         unbecome_root();
03455                 }
03456                 if (acl_set_support && ret == false) {
03457                         DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
03458                         free_canon_ace_list(file_ace_list);
03459                         free_canon_ace_list(dir_ace_list);
03460                         return ret;
03461                 }
03462         }
03463  
03464         if (acl_perms && acl_set_support && fsp->is_directory) {
03465                 if (dir_ace_list) {
03466                         if (set_acl_as_root) {
03467                                 become_root();
03468                         }
03469                         ret = set_canon_ace_list(fsp, dir_ace_list, True, sbuf.st_gid, &acl_set_support);
03470                         if (set_acl_as_root) {
03471                                 unbecome_root();
03472                         }
03473                         if (ret == False) {
03474                                 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
03475                                 free_canon_ace_list(file_ace_list);
03476                                 free_canon_ace_list(dir_ace_list);
03477                                 return ret;
03478                         }
03479                 } else {
03480                         int sret = -1;
03481  
03482                         /*
03483                          * No default ACL - delete one if it exists.
03484                          */
03485  
03486                         if (set_acl_as_root) {
03487                                 become_root();
03488                         }
03489                         sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
03490                         if (set_acl_as_root) {
03491                                 unbecome_root();
03492                         }
03493                         if (sret == -1) {
03494                                 if (acl_group_override(conn, sbuf.st_gid, fsp->fsp_name)) {
03495                                         DEBUG(5,("set_nt_acl: acl group control on and "
03496                                                 "current user in file %s primary group. Override delete_def_acl\n",
03497                                                 fsp->fsp_name ));
03498  
03499                                         become_root();
03500                                         sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
03501                                         unbecome_root();
03502                                 }
03503  
03504                                 if (sret == -1) {
03505                                         DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
03506                                         free_canon_ace_list(file_ace_list);
03507                                         free_canon_ace_list(dir_ace_list);
03508                                         return False;
03509                                 }
03510                         }
03511                 }
03512         }
03513  
03514         if (acl_set_support) {
03515                 if (set_acl_as_root) {
03516                         become_root();
03517                 }
03518                 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
03519                                 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
03520                 if (set_acl_as_root) {
03521                         unbecome_root();
03522                 }
03523         }
03524  
03525         /*
03526          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
03527          */
03528  
03529         if(!acl_set_support && acl_perms) {
03530                 mode_t posix_perms;
03531  
03532                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
03533                         free_canon_ace_list(file_ace_list);
03534                         free_canon_ace_list(dir_ace_list);
03535                         DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
03536                                 fsp->fsp_name ));
03537                         return False;
03538                 }
03539  
03540                 if (orig_mode != posix_perms) {
03541                         int sret = -1;
03542  
03543                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
03544                                 fsp->fsp_name, (unsigned int)posix_perms ));
03545  
03546                         if (set_acl_as_root) {
03547                                 become_root();
03548                         }
03549                         sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
03550                         if (set_acl_as_root) {
03551                                 unbecome_root();
03552                         }
03553                         if(sret == -1) {
03554                                 if (acl_group_override(conn, sbuf.st_gid, fsp->fsp_name)) {
03555                                         DEBUG(5,("set_nt_acl: acl group control on and "
03556                                                 "current user in file %s primary group. Override chmod\n",
03557                                                 fsp->fsp_name ));
03558  
03559                                         become_root();
03560                                         sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
03561                                         unbecome_root();
03562                                 }
03563  
03564                                 if (sret == -1) {
03565                                         DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
03566                                                 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
03567                                         free_canon_ace_list(file_ace_list);
03568                                         free_canon_ace_list(dir_ace_list);
03569                                         return False;
03570                                 }
03571                         }
03572                 }
03573         }
03574  
03575         free_canon_ace_list(file_ace_list);
03576         free_canon_ace_list(dir_ace_list);
03577         return True;
03578 }
03579 
03580 /****************************************************************************
03581  Get the actual group bits stored on a file with an ACL. Has no effect if
03582  the file has no ACL. Needed in dosmode code where the stat() will return
03583  the mask bits, not the real group bits, for a file with an ACL.
03584 ****************************************************************************/
03585 
03586 int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
03587 {
03588         int entry_id = SMB_ACL_FIRST_ENTRY;
03589         SMB_ACL_ENTRY_T entry;
03590         SMB_ACL_T posix_acl;
03591         int result = -1;
03592 
03593         posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
03594         if (posix_acl == (SMB_ACL_T)NULL)
03595                 return -1;
03596 
03597         while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
03598                 SMB_ACL_TAG_T tagtype;
03599                 SMB_ACL_PERMSET_T permset;
03600 
03601                 /* get_next... */
03602                 if (entry_id == SMB_ACL_FIRST_ENTRY)
03603                         entry_id = SMB_ACL_NEXT_ENTRY;
03604 
03605                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
03606                         break;
03607 
03608                 if (tagtype == SMB_ACL_GROUP_OBJ) {
03609                         if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
03610                                 break;
03611                         } else {
03612                                 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
03613                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
03614                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
03615                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
03616                                 result = 0;
03617                                 break;
03618                         }
03619                 }
03620         }
03621         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
03622         return result;
03623 }
03624 
03625 /****************************************************************************
03626  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
03627  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
03628 ****************************************************************************/
03629 
03630 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
03631 {
03632         int entry_id = SMB_ACL_FIRST_ENTRY;
03633         SMB_ACL_ENTRY_T entry;
03634         int num_entries = 0;
03635 
03636         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
03637                 SMB_ACL_TAG_T tagtype;
03638                 SMB_ACL_PERMSET_T permset;
03639                 mode_t perms;
03640 
03641                 /* get_next... */
03642                 if (entry_id == SMB_ACL_FIRST_ENTRY)
03643                         entry_id = SMB_ACL_NEXT_ENTRY;
03644 
03645                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
03646                         return -1;
03647 
03648                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
03649                         return -1;
03650 
03651                 num_entries++;
03652 
03653                 switch(tagtype) {
03654                         case SMB_ACL_USER_OBJ:
03655                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
03656                                 break;
03657                         case SMB_ACL_GROUP_OBJ:
03658                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
03659                                 break;
03660                         case SMB_ACL_MASK:
03661                                 /*
03662                                  * FIXME: The ACL_MASK entry permissions should really be set to
03663                                  * the union of the permissions of all ACL_USER,
03664                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
03665                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
03666                                  */
03667                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
03668                                 break;
03669                         case SMB_ACL_OTHER:
03670                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
03671                                 break;
03672                         default:
03673                                 continue;
03674                 }
03675 
03676                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
03677                         return -1;
03678 
03679                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
03680                         return -1;
03681         }
03682 
03683         /*
03684          * If this is a simple 3 element ACL or no elements then it's a standard
03685          * UNIX permission set. Just use chmod...       
03686          */
03687 
03688         if ((num_entries == 3) || (num_entries == 0))
03689                 return -1;
03690 
03691         return 0;
03692 }
03693 
03694 /****************************************************************************
03695  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
03696  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
03697  resulting ACL on TO.  Note that name is in UNIX character set.
03698 ****************************************************************************/
03699 
03700 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
03701 {
03702         SMB_ACL_T posix_acl = NULL;
03703         int ret = -1;
03704 
03705         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
03706                 return -1;
03707 
03708         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
03709                 goto done;
03710 
03711         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
03712 
03713  done:
03714 
03715         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
03716         return ret;
03717 }
03718 
03719 /****************************************************************************
03720  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
03721  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
03722  Note that name is in UNIX character set.
03723 ****************************************************************************/
03724 
03725 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
03726 {
03727         return copy_access_acl(conn, name, name, mode);
03728 }
03729 
03730 /****************************************************************************
03731  If the parent directory has no default ACL but it does have an Access ACL,
03732  inherit this Access ACL to file name.
03733 ****************************************************************************/
03734 
03735 int inherit_access_acl(connection_struct *conn, const char *inherit_from_dir,
03736                        const char *name, mode_t mode)
03737 {
03738         if (directory_has_default_acl(conn, inherit_from_dir))
03739                 return 0;
03740 
03741         return copy_access_acl(conn, inherit_from_dir, name, mode);
03742 }
03743 
03744 /****************************************************************************
03745  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
03746  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
03747 ****************************************************************************/
03748 
03749 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
03750 {
03751         connection_struct *conn = fsp->conn;
03752         SMB_ACL_T posix_acl = NULL;
03753         int ret = -1;
03754 
03755         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
03756                 return -1;
03757 
03758         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
03759                 goto done;
03760 
03761         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
03762 
03763   done:
03764 
03765         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
03766         return ret;
03767 }
03768 
03769 /****************************************************************************
03770  Check for an existing default POSIX ACL on a directory.
03771 ****************************************************************************/
03772 
03773 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
03774 {
03775         SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
03776         BOOL has_acl = False;
03777         SMB_ACL_ENTRY_T entry;
03778 
03779         if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
03780                 has_acl = True;
03781         }
03782 
03783         if (def_acl) {
03784                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
03785         }
03786         return has_acl;
03787 }
03788 
03789 /****************************************************************************
03790  Map from wire type to permset.
03791 ****************************************************************************/
03792 
03793 static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
03794 {
03795         if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
03796                 return False;
03797         }
03798 
03799         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1) {
03800                 return False;
03801         }
03802 
03803         if (wire_perm & SMB_POSIX_ACL_READ) {
03804                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
03805                         return False;
03806                 }
03807         }
03808         if (wire_perm & SMB_POSIX_ACL_WRITE) {
03809                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
03810                         return False;
03811                 }
03812         }
03813         if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
03814                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
03815                         return False;
03816                 }
03817         }
03818         return True;
03819 }
03820 
03821 /****************************************************************************
03822  Map from wire type to tagtype.
03823 ****************************************************************************/
03824 
03825 static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
03826 {
03827         switch (wire_tt) {
03828                 case SMB_POSIX_ACL_USER_OBJ:
03829                         *p_tt = SMB_ACL_USER_OBJ;
03830                         break;
03831                 case SMB_POSIX_ACL_USER:
03832                         *p_tt = SMB_ACL_USER;
03833                         break;
03834                 case SMB_POSIX_ACL_GROUP_OBJ:
03835                         *p_tt = SMB_ACL_GROUP_OBJ;
03836                         break;
03837                 case SMB_POSIX_ACL_GROUP:
03838                         *p_tt = SMB_ACL_GROUP;
03839                         break;
03840                 case SMB_POSIX_ACL_MASK:
03841                         *p_tt = SMB_ACL_MASK;
03842                         break;
03843                 case SMB_POSIX_ACL_OTHER:
03844                         *p_tt = SMB_ACL_OTHER;
03845                         break;
03846                 default:
03847                         return False;
03848         }
03849         return True;
03850 }
03851 
03852 /****************************************************************************
03853  Create a new POSIX acl from wire permissions.
03854  FIXME ! How does the share mask/mode fit into this.... ?
03855 ****************************************************************************/
03856 
03857 static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
03858 {
03859         unsigned int i;
03860         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
03861 
03862         if (the_acl == NULL) {
03863                 return NULL;
03864         }
03865 
03866         for (i = 0; i < num_acls; i++) {
03867                 SMB_ACL_ENTRY_T the_entry;
03868                 SMB_ACL_PERMSET_T the_permset;
03869                 SMB_ACL_TAG_T tag_type;
03870 
03871                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
03872                         DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
03873                                 i, strerror(errno) ));
03874                         goto fail;
03875                 }
03876 
03877                 if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
03878                         DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
03879                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
03880                         goto fail;
03881                 }
03882 
03883                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
03884                         DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
03885                                 i, strerror(errno) ));
03886                         goto fail;
03887                 }
03888 
03889                 /* Get the permset pointer from the new ACL entry. */
03890                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
03891                         DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
03892                                 i, strerror(errno) ));
03893                         goto fail;
03894                 }
03895 
03896                 /* Map from wire to permissions. */
03897                 if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
03898                         DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
03899                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
03900                         goto fail;
03901                 }
03902 
03903                 /* Now apply to the new ACL entry. */
03904                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
03905                         DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
03906                                 i, strerror(errno) ));
03907                         goto fail;
03908                 }
03909 
03910                 if (tag_type == SMB_ACL_USER) {
03911                         uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
03912                         uid_t uid = (uid_t)uidval;
03913                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
03914                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
03915                                         (unsigned int)uid, i, strerror(errno) ));
03916                                 goto fail;
03917                         }
03918                 }
03919 
03920                 if (tag_type == SMB_ACL_GROUP) {
03921                         uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
03922                         gid_t gid = (uid_t)gidval;
03923                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
03924                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
03925                                         (unsigned int)gid, i, strerror(errno) ));
03926                                 goto fail;
03927                         }
03928                 }
03929         }
03930 
03931         return the_acl;
03932 
03933  fail:
03934 
03935         if (the_acl != NULL) {
03936                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
03937         }
03938         return NULL;
03939 }
03940 
03941 /****************************************************************************
03942  Calls from UNIX extensions - Default POSIX ACL set.
03943  If num_def_acls == 0 and not a directory just return. If it is a directory
03944  and num_def_acls == 0 then remove the default acl. Else set the default acl
03945  on the directory.
03946 ****************************************************************************/
03947 
03948 BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
03949                                 uint16 num_def_acls, const char *pdata)
03950 {
03951         SMB_ACL_T def_acl = NULL;
03952 
03953         if (num_def_acls && !S_ISDIR(psbuf->st_mode)) {
03954                 DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
03955                 errno = EISDIR;
03956                 return False;
03957         }
03958 
03959         if (!num_def_acls) {
03960                 /* Remove the default ACL. */
03961                 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
03962                         DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
03963                                 fname, strerror(errno) ));
03964                         return False;
03965                 }
03966                 return True;
03967         }
03968 
03969         if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
03970                 return False;
03971         }
03972 
03973         if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
03974                 DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
03975                         fname, strerror(errno) ));
03976                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
03977                 return False;
03978         }
03979 
03980         DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
03981         SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
03982         return True;
03983 }
03984 
03985 /****************************************************************************
03986  Remove an ACL from a file. As we don't have acl_delete_entry() available
03987  we must read the current acl and copy all entries except MASK, USER and GROUP
03988  to a new acl, then set that. This (at least on Linux) causes any ACL to be
03989  removed.
03990  FIXME ! How does the share mask/mode fit into this.... ?
03991 ****************************************************************************/
03992 
03993 static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
03994 {
03995         SMB_ACL_T file_acl = NULL;
03996         int entry_id = SMB_ACL_FIRST_ENTRY;
03997         SMB_ACL_ENTRY_T entry;
03998         BOOL ret = False;
03999         /* Create a new ACL with only 3 entries, u/g/w. */
04000         SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
04001         SMB_ACL_ENTRY_T user_ent = NULL;
04002         SMB_ACL_ENTRY_T group_ent = NULL;
04003         SMB_ACL_ENTRY_T other_ent = NULL;
04004 
04005         if (new_file_acl == NULL) {
04006                 DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
04007                 return False;
04008         }
04009 
04010         /* Now create the u/g/w entries. */
04011         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
04012                 DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
04013                         fname, strerror(errno) ));
04014                 goto done;
04015         }
04016         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
04017                 DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
04018                         fname, strerror(errno) ));
04019                 goto done;
04020         }
04021 
04022         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
04023                 DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
04024                         fname, strerror(errno) ));
04025                 goto done;
04026         }
04027         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
04028                 DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
04029                         fname, strerror(errno) ));
04030                 goto done;
04031         }
04032 
04033         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
04034                 DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
04035                         fname, strerror(errno) ));
04036                 goto done;
04037         }
04038         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
04039                 DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
04040                         fname, strerror(errno) ));
04041                 goto done;
04042         }
04043 
04044         /* Get the current file ACL. */
04045         if (fsp && fsp->fh->fd != -1) {
04046                 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
04047         } else {
04048                 file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
04049         }
04050 
04051         if (file_acl == NULL) {
04052                 /* This is only returned if an error occurred. Even for a file with
04053                    no acl a u/g/w acl should be returned. */
04054                 DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
04055                         fname, strerror(errno) ));
04056                 goto done;
04057         }
04058 
04059         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
04060                 SMB_ACL_TAG_T tagtype;
04061                 SMB_ACL_PERMSET_T permset;
04062 
04063                 /* get_next... */
04064                 if (entry_id == SMB_ACL_FIRST_ENTRY)
04065                         entry_id = SMB_ACL_NEXT_ENTRY;
04066 
04067                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
04068                         DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
04069                                 fname, strerror(errno) ));
04070                         goto done;
04071                 }
04072 
04073                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
04074                         DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
04075                                 fname, strerror(errno) ));
04076                         goto done;
04077                 }
04078 
04079                 if (tagtype == SMB_ACL_USER_OBJ) {
04080                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
04081                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
04082                                         fname, strerror(errno) ));
04083                         }
04084                 } else if (tagtype == SMB_ACL_GROUP_OBJ) {
04085                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
04086                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
04087                                         fname, strerror(errno) ));
04088                         }
04089                 } else if (tagtype == SMB_ACL_OTHER) {
04090                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
04091                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
04092                                         fname, strerror(errno) ));
04093                         }
04094                 }
04095         }
04096 
04097         /* Set the new empty file ACL. */
04098         if (fsp && fsp->fh->fd != -1) {
04099                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, new_file_acl) == -1) {
04100                         DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
04101                                 fname, strerror(errno) ));
04102                         goto done;
04103                 }
04104         } else {
04105                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, new_file_acl) == -1) {
04106                         DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
04107                                 fname, strerror(errno) ));
04108                         goto done;
04109                 }
04110         }
04111 
04112         ret = True;
04113 
04114  done:
04115 
04116         if (file_acl) {
04117                 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
04118         }
04119         if (new_file_acl) {
04120                 SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
04121         }
04122         return ret;
04123 }
04124 
04125 /****************************************************************************
04126  Calls from UNIX extensions - POSIX ACL set.
04127  If num_def_acls == 0 then read/modify/write acl after removing all entries
04128  except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
04129 ****************************************************************************/
04130 
04131 BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
04132 {
04133         SMB_ACL_T file_acl = NULL;
04134 
04135         if (!num_acls) {
04136                 /* Remove the ACL from the file. */
04137                 return remove_posix_acl(conn, fsp, fname);
04138         }
04139 
04140         if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
04141                 return False;
04142         }
04143 
04144         if (fsp && fsp->fh->fd != -1) {
04145                 /* The preferred way - use an open fd. */
04146                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, file_acl) == -1) {
04147                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
04148                                 fname, strerror(errno) ));
04149                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
04150                         return False;
04151                 }
04152         } else {
04153                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
04154                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
04155                                 fname, strerror(errno) ));
04156                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
04157                         return False;
04158                 }
04159         }
04160 
04161         DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
04162         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
04163         return True;
04164 }
04165 
04166 /****************************************************************************
04167  Helper function that gets a security descriptor by connection and
04168  file name.
04169  NOTE: This is transitional, in the sense that SMB_VFS_GET_NT_ACL really
04170  should *not* get a files_struct pointer but a connection_struct ptr
04171  (automatic by the vfs handle) and the file name and _use_ that!
04172 ****************************************************************************/
04173 static NTSTATUS conn_get_nt_acl(TALLOC_CTX *mem_ctx,
04174                                 struct connection_struct *conn,
04175                                 const char *fname,
04176                                 SMB_STRUCT_STAT *psbuf,
04177                                 struct security_descriptor_info **psd)
04178 {
04179         NTSTATUS status;
04180         struct files_struct *fsp = NULL;
04181         struct security_descriptor_info *secdesc = NULL;
04182         size_t secdesc_size;
04183 
04184         if (!VALID_STAT(*psbuf)) {
04185                 if (SMB_VFS_STAT(conn, fname, psbuf) != 0) {
04186                         return map_nt_error_from_unix(errno);
04187                 }
04188         }
04189 
04190         /* fake a files_struct ptr: */
04191 
04192         if (S_ISDIR(psbuf->st_mode)) {
04193                 status = open_directory(conn, fname, psbuf,
04194                                         READ_CONTROL_ACCESS,
04195                                         FILE_SHARE_READ|FILE_SHARE_WRITE,
04196                                         FILE_OPEN,
04197                                         0,
04198                                         FILE_ATTRIBUTE_DIRECTORY,
04199                                         NULL, &fsp);
04200         }
04201         else {
04202                 status = open_file_stat(conn, fname, psbuf, &fsp);
04203         }
04204 
04205         if (!NT_STATUS_IS_OK(status)) {
04206                 DEBUG(3, ("Unable to open file %s: %s\n", fname,
04207                           nt_errstr(status)));
04208                 return status;
04209         }
04210 
04211         secdesc_size = SMB_VFS_GET_NT_ACL(fsp, fname,
04212                                           (OWNER_SECURITY_INFORMATION |
04213                                            GROUP_SECURITY_INFORMATION |
04214                                            DACL_SECURITY_INFORMATION),
04215                                           &secdesc);
04216         if (secdesc_size == 0) {
04217                 DEBUG(5, ("Unable to get NT ACL for file %s\n", fname));
04218                 status = NT_STATUS_ACCESS_DENIED;
04219                 goto done;
04220         }
04221 
04222         *psd = talloc_move(mem_ctx, &secdesc);
04223         status = NT_STATUS_OK;
04224 
04225 done:
04226         close_file(fsp, NORMAL_CLOSE);
04227         return status;
04228 }
04229 
04230 static BOOL can_access_file_acl(struct connection_struct *conn,
04231                                 const char * fname, SMB_STRUCT_STAT *psbuf,
04232                                 uint32_t access_mask)
04233 {
04234         BOOL result;
04235         NTSTATUS status;
04236         uint32_t access_granted;
04237         struct security_descriptor_info *secdesc = NULL;
04238 
04239         status = conn_get_nt_acl(tmp_talloc_ctx(), conn, fname, psbuf, &secdesc);
04240         if (!NT_STATUS_IS_OK(status)) {
04241                 DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status)));
04242                 return False;
04243         }
04244 
04245         result = se_access_check(secdesc, current_user.nt_user_token,
04246                                  access_mask, &access_granted, &status);
04247         TALLOC_FREE(secdesc);
04248         return result;
04249 }
04250 
04251 /****************************************************************************
04252  Actually emulate the in-kernel access checking for delete access. We need
04253  this to successfully return ACCESS_DENIED on a file open for delete access.
04254 ****************************************************************************/
04255 
04256 BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
04257 {
04258         SMB_STRUCT_STAT sbuf;  
04259         pstring dname;
04260 
04261         if (!CAN_WRITE(conn)) {
04262                 return False;
04263         }
04264 
04265         /* Get the parent directory permission mask and owners. */
04266         pstrcpy(dname, parent_dirname(fname));
04267         if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
04268                 return False;
04269         }
04270 
04271         /* fast paths first */
04272 
04273         if (!S_ISDIR(sbuf.st_mode)) {
04274                 return False;
04275         }
04276         if (current_user.ut.uid == 0 || conn->admin_user) {
04277                 /* I'm sorry sir, I didn't know you were root... */
04278                 return True;
04279         }
04280 
04281         /* Check primary owner write access. */
04282         if (current_user.ut.uid == sbuf.st_uid) {
04283                 return (sbuf.st_mode & S_IWUSR) ? True : False;
04284         }
04285 
04286 #ifdef S_ISVTX
04287         /* sticky bit means delete only by owner or root. */
04288         if (sbuf.st_mode & S_ISVTX) {
04289                 SMB_STRUCT_STAT sbuf_file;  
04290                 if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
04291                         if (errno == ENOENT) {
04292                                 /* If the file doesn't already exist then
04293                                  * yes we'll be able to delete it. */
04294                                 return True;
04295                         }
04296                         return False;
04297                 }
04298                 /*
04299                  * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com>
04300                  * for bug #3348. Don't assume owning sticky bit
04301                  * directory means write access allowed.
04302                  */
04303                 if (current_user.ut.uid != sbuf_file.st_uid) {
04304                         return False;
04305                 }
04306         }
04307 #endif
04308 
04309         /* now for ACL checks */
04310 
04311         return can_access_file_acl(conn, dname, &sbuf, FILE_WRITE_DATA);
04312 }
04313 
04314 /****************************************************************************
04315  Actually emulate the in-kernel access checking for read/write access. We need
04316  this to successfully check for ability to write for dos filetimes.
04317  Note this doesn't take into account share write permissions.
04318 ****************************************************************************/
04319 
04320 BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
04321 {
04322         if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) {
04323                 return False;
04324         }
04325         access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA);
04326 
04327         /* some fast paths first */
04328 
04329         DEBUG(10,("can_access_file: requesting 0x%x on file %s\n",
04330                 (unsigned int)access_mask, fname ));
04331 
04332         if (current_user.ut.uid == 0 || conn->admin_user) {
04333                 /* I'm sorry sir, I didn't know you were root... */
04334                 return True;
04335         }
04336 
04337         if (!VALID_STAT(*psbuf)) {
04338                 /* Get the file permission mask and owners. */
04339                 if(SMB_VFS_STAT(conn, fname, psbuf) != 0) {
04340                         return False;
04341                 }
04342         }
04343 
04344         /* Check primary owner access. */
04345         if (current_user.ut.uid == psbuf->st_uid) {
04346                 switch (access_mask) {
04347                         case FILE_READ_DATA:
04348                                 return (psbuf->st_mode & S_IRUSR) ? True : False;
04349 
04350                         case FILE_WRITE_DATA:
04351                                 return (psbuf->st_mode & S_IWUSR) ? True : False;
04352 
04353                         default: /* FILE_READ_DATA|FILE_WRITE_DATA */
04354 
04355                                 if ((psbuf->st_mode & (S_IWUSR|S_IRUSR)) == (S_IWUSR|S_IRUSR)) {
04356                                         return True;
04357                                 } else {
04358                                         return False;
04359                                 }
04360                 }
04361         }
04362 
04363         /* now for ACL checks */
04364 
04365         return can_access_file_acl(conn, fname, psbuf, access_mask);
04366 }
04367 
04368 /****************************************************************************
04369  Userspace check for write access.
04370  Note this doesn't take into account share write permissions.
04371 ****************************************************************************/
04372 
04373 BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
04374 {
04375         return can_access_file(conn, fname, psbuf, FILE_WRITE_DATA);
04376 }
04377 
04378 /********************************************************************
04379  Pull the NT ACL from a file on disk or the OpenEventlog() access
04380  check.  Caller is responsible for freeing the returned security
04381  descriptor via TALLOC_FREE().  This is designed for dealing with 
04382  user space access checks in smbd outside of the VFS.  For example,
04383  checking access rights in OpenEventlog().
04384  
04385  Assume we are dealing with files (for now)
04386 ********************************************************************/
04387 
04388 SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
04389 {
04390         SEC_DESC *psd, *ret_sd;
04391         connection_struct conn;
04392         files_struct finfo;
04393         struct fd_handle fh;
04394         pstring path;
04395         pstring filename;
04396         
04397         ZERO_STRUCT( conn );
04398         
04399         if ( !(conn.mem_ctx = talloc_init( "novfs_get_nt_acl" )) ) {
04400                 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
04401                 return NULL;
04402         }
04403 
04404         if (!(conn.params = TALLOC_P(conn.mem_ctx, struct share_params))) {
04405                 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
04406                 TALLOC_FREE(conn.mem_ctx);
04407                 return NULL;
04408         }
04409 
04410         conn.params->service = -1;
04411         
04412         pstrcpy( path, "/" );
04413         set_conn_connectpath(&conn, path);
04414         
04415         if (!smbd_vfs_init(&conn)) {
04416                 DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
04417                 conn_free_internal( &conn );
04418                 return NULL;
04419         }
04420         
04421         ZERO_STRUCT( finfo );
04422         ZERO_STRUCT( fh );
04423         
04424         finfo.fnum = -1;
04425         finfo.conn = &conn;
04426         finfo.fh = &fh;
04427         finfo.fh->fd = -1;
04428         pstrcpy( filename, fname );
04429         finfo.fsp_name = filename;
04430         
04431         if (get_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd ) == 0) {
04432                 DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
04433                 conn_free_internal( &conn );
04434                 return NULL;
04435         }
04436         
04437         ret_sd = dup_sec_desc( ctx, psd );
04438         
04439         conn_free_internal( &conn );
04440         
04441         return ret_sd;
04442 }

Sambaに対してSat Aug 29 21:23:25 2009に生成されました。  doxygen 1.4.7