pdb_samba_dsdb: implement pdb_samba_dsdb_enum_trusteddoms()
[bbaumbach/samba-autobuild/.git] / source3 / passdb / machine_sid.c
index 34b0c742087267ff998dc9a5151d7eb09c3f8470..cdef1d61c976bd3c59a94cd3485238be20946752 100644 (file)
-/* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+/*
+   Unix SMB/CIFS implementation.
    Password and authentication handling
-   Copyright (C) Jeremy Allison                1996-1998
-   Copyright (C) Luke Kenneth Casson Leighton  1996-1998
+   Copyright (C) Jeremy Allison                1996-2002
+   Copyright (C) Andrew Tridgell               2002
    Copyright (C) Gerald (Jerry) Carter         2000
-      
+   Copyright (C) Stefan (metze) Metzmacher     2002
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "passdb/machine_sid.h"
+#include "secrets.h"
+#include "dbwrap/dbwrap.h"
+#include "../libcli/security/security.h"
+
+/* NOTE! the global_sam_sid is the SID of our local SAM. This is only
+   equal to the domain SID when we are a DC, otherwise its our
+   workstation SID */
+static struct dom_sid *global_sam_sid=NULL;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_PASSDB
 
 /****************************************************************************
- Read the machine SID from a file.
+ Read a SID from a file. This is for compatibility with the old MACHINE.SID
+ style of SID storage
 ****************************************************************************/
 
-static BOOL read_sid_from_file(int fd, char *sid_file)
+static bool read_sid_from_file(const char *fname, struct dom_sid *sid)
 {
-  fstring fline;
+       char **lines;
+       int numlines;
+       bool ret;
 
-  memset(fline, '\0', sizeof(fline));
+       lines = file_lines_load(fname, &numlines,0, NULL);
 
-  if(read(fd, fline, sizeof(fline) -1 ) < 0) {
-    DEBUG(0,("unable to read file %s. Error was %s\n",
-           sid_file, strerror(errno) ));
-    return False;
-  }
+       if (!lines || numlines < 1) {
+               TALLOC_FREE(lines);
+               return False;
+       }
 
-  /*
-   * Convert to the machine SID.
-   */
+       ret = string_to_sid(sid, lines[0]);
+       TALLOC_FREE(lines);
+       return ret;
+}
 
-  fline[sizeof(fline)-1] = '\0';
-  if(!string_to_sid( &global_sam_sid, fline)) {
-    DEBUG(0,("unable to generate machine SID.\n"));
-    return False;
-  }
+/*
+  generate a random sid - used to build our own sid if we don't have one
+*/
+static void generate_random_sid(struct dom_sid *sid)
+{
+       int i;
+       uchar raw_sid_data[12];
 
-  return True;
+       ZERO_STRUCTP(sid);
+
+       sid->sid_rev_num = 1;
+       sid->id_auth[5] = 5;
+       sid->num_auths = 0;
+       sid->sub_auths[sid->num_auths++] = 21;
+
+       generate_random_buffer(raw_sid_data, 12);
+       for (i = 0; i < 3; i++)
+               sid->sub_auths[sid->num_auths++] = IVAL(raw_sid_data, i*4);
 }
 
 /****************************************************************************
- Generate the global machine sid. Look for the MACHINE.SID file first, if
- not found then look in smb.conf and use it to create the MACHINE.SID file.
- Note this function will be replaced soon. JRA.
+ Generate the global machine sid.
 ****************************************************************************/
 
-BOOL pdb_generate_sam_sid(void)
+static struct dom_sid *pdb_generate_sam_sid(void)
 {
-       int fd;
-       char *p;
-       pstring sid_file;
-       fstring sid_string;
-       SMB_STRUCT_STAT st;
-       BOOL overwrite_bad_sid = False;
-
-       generate_wellknown_sids();
-
-       pstrcpy(sid_file, lp_smb_passwd_file());
-       p = strrchr_m(sid_file, '/');
-       if(p != NULL) {
-               *++p = '\0';
-       }
+       struct dom_sid domain_sid;
+       char *fname = NULL;
+       struct dom_sid *sam_sid;
 
-       if (!directory_exist(sid_file, NULL)) {
-               if (mkdir(sid_file, 0700) != 0) {
-                       DEBUG(0,("can't create private directory %s : %s\n",
-                                sid_file, strerror(errno)));
-                       return False;
+       if(!(sam_sid=SMB_MALLOC_P(struct dom_sid)))
+               return NULL;
+
+       if ( IS_DC ) {
+               if (secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+                       sid_copy(sam_sid, &domain_sid);
+                       return sam_sid;
                }
        }
 
-       pstrcat(sid_file, "MACHINE.SID");
-    
-       if((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
-               DEBUG(0,("unable to open or create file %s. Error was %s\n",
-                        sid_file, strerror(errno) ));
-               return False;
-       } 
-  
-       /*
-        * Check if the file contains data.
-        */
-       
-       if(sys_fstat( fd, &st) < 0) {
-               DEBUG(0,("unable to stat file %s. Error was %s\n",
-                        sid_file, strerror(errno) ));
-               close(fd);
-               return False;
-       } 
-  
-       if(st.st_size > 0) {
-               /*
-                * We have a valid SID - read it.
-                */
-               if(!read_sid_from_file( fd, sid_file)) {
-                       DEBUG(0,("unable to read file %s. Error was %s\n",
-                                sid_file, strerror(errno) ));
-                       close(fd);
-                       return False;
+       if (secrets_fetch_domain_sid(lp_netbios_name(), sam_sid)) {
+
+               /* We got our sid. If not a pdc/bdc, we're done. */
+               if ( !IS_DC )
+                       return sam_sid;
+
+               if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+
+                       /* No domain sid and we're a pdc/bdc. Store it */
+
+                       if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+                               DEBUG(0,("pdb_generate_sam_sid: Can't store domain SID as a pdc/bdc.\n"));
+                               SAFE_FREE(sam_sid);
+                               return NULL;
+                       }
+                       return sam_sid;
                }
 
-               /*
-                * JRA. Reversed the sense of this test now that I have
-                * actually done this test *personally*. One more reason
-                * to never trust third party information you have not
-                * independently verified.... sigh. JRA.
-                */
-
-               if(global_sam_sid.num_auths > 0 && global_sam_sid.sub_auths[0] == 0x21) {
-                       /*
-                        * Fix and re-write...
-                        */
-                       overwrite_bad_sid = True;
-                       global_sam_sid.sub_auths[0] = 21;
-                       DEBUG(5,("pdb_generate_sam_sid: Old (incorrect) sid id_auth of hex 21 \
-detected - re-writing to be decimal 21 instead.\n" ));
-                       sid_to_string(sid_string, &global_sam_sid);
-                       if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) {
-                               DEBUG(0,("unable to seek file file %s. Error was %s\n",
-                                        sid_file, strerror(errno) ));
-                               close(fd);
-                               return False;
+               if (!dom_sid_equal(&domain_sid, sam_sid)) {
+
+                       /* Domain name sid doesn't match global sam sid. Re-store domain sid as 'local' sid. */
+
+                       DEBUG(0,("pdb_generate_sam_sid: Mismatched SIDs as a pdc/bdc.\n"));
+                       if (!secrets_store_domain_sid(lp_netbios_name(), &domain_sid)) {
+                               DEBUG(0,("pdb_generate_sam_sid: Can't re-store domain SID for local sid as PDC/BDC.\n"));
+                               SAFE_FREE(sam_sid);
+                               return NULL;
                        }
-               } else {
-                       close(fd);
-                       return True;
+                       return sam_sid;
                }
-       } else {
-               /*
-                * The file contains no data - we need to generate our
-                * own sid.
-                * Generate the new sid data & turn it into a string.
-                */
-               int i;
-               uchar raw_sid_data[12];
-               DOM_SID mysid;
-
-               memset((char *)&mysid, '\0', sizeof(DOM_SID));
-               mysid.sid_rev_num = 1;
-               mysid.id_auth[5] = 5;
-               mysid.num_auths = 0;
-               mysid.sub_auths[mysid.num_auths++] = 21;
-
-               generate_random_buffer( raw_sid_data, 12, True);
-               for( i = 0; i < 3; i++)
-                       mysid.sub_auths[mysid.num_auths++] = IVAL(raw_sid_data, i*4);
-
-               sid_to_string(sid_string, &mysid);
-       } 
-       
-       fstrcat(sid_string, "\n");
-       
-       /*
-        * Ensure our new SID is valid.
-        */
-       
-       if(!string_to_sid( &global_sam_sid, sid_string)) {
-               DEBUG(0,("unable to generate machine SID.\n"));
-               return False;
-       } 
-  
-       /*
-        * Do an exclusive blocking lock on the file.
-        */
-       
-       if(!do_file_lock( fd, 60, F_WRLCK)) {
-               DEBUG(0,("unable to lock file %s. Error was %s\n",
-                        sid_file, strerror(errno) ));
-               close(fd);
-               return False;
-       } 
-       if(!overwrite_bad_sid) {
-               /*
-                * At this point we have a blocking lock on the SID
-                * file - check if in the meantime someone else wrote
-                * SID data into the file. If so - they were here first,
-                * use their data.
-                */
-       
-               if(sys_fstat( fd, &st) < 0) {
-                       DEBUG(0,("unable to stat file %s. Error was %s\n",
-                                sid_file, strerror(errno) ));
-                       close(fd);
-                       return False;
-               } 
-  
-               if(st.st_size > 0) {
-                       /*
-                        * Unlock as soon as possible to reduce
-                        * contention on the exclusive lock.
-                        */ 
-                       do_file_lock( fd, 60, F_UNLCK);
-               
-                       /*
-                        * We have a valid SID - read it.
-                        */
-               
-                       if(!read_sid_from_file( fd, sid_file)) {
-                               DEBUG(0,("unable to read file %s. Error was %s\n",
-                                        sid_file, strerror(errno) ));
-                               close(fd);
-                               return False;
+
+               return sam_sid;
+       }
+
+       /* check for an old MACHINE.SID file for backwards compatibility */
+       if (asprintf(&fname, "%s/MACHINE.SID", lp_private_dir()) == -1) {
+               SAFE_FREE(sam_sid);
+               return NULL;
+       }
+
+       if (read_sid_from_file(fname, sam_sid)) {
+               /* remember it for future reference and unlink the old MACHINE.SID */
+               if (!secrets_store_domain_sid(lp_netbios_name(), sam_sid)) {
+                       DEBUG(0,("pdb_generate_sam_sid: Failed to store SID from file.\n"));
+                       SAFE_FREE(fname);
+                       SAFE_FREE(sam_sid);
+                       return NULL;
+               }
+               unlink(fname);
+               if ( !IS_DC ) {
+                       if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+                               DEBUG(0,("pdb_generate_sam_sid: Failed to store domain SID from file.\n"));
+                               SAFE_FREE(fname);
+                               SAFE_FREE(sam_sid);
+                               return NULL;
                        }
-                       close(fd);
-                       return True;
-               } 
+               }
+
+               /* Stored the old sid from MACHINE.SID successfully.*/
+               SAFE_FREE(fname);
+               return sam_sid;
        }
-       
-       /*
-        * The file is still empty and we have an exlusive lock on it,
-        * or we're fixing an earlier mistake.
-        * Write out out SID data into the file.
-        */
+
+       SAFE_FREE(fname);
+
+       /* we don't have the SID in secrets.tdb, we will need to
+           generate one and save it */
+       generate_random_sid(sam_sid);
+
+       if (!secrets_store_domain_sid(lp_netbios_name(), sam_sid)) {
+               DEBUG(0,("pdb_generate_sam_sid: Failed to store generated machine SID.\n"));
+               SAFE_FREE(sam_sid);
+               return NULL;
+       }
+       if ( IS_DC ) {
+               if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
+                       DEBUG(0,("pdb_generate_sam_sid: Failed to store generated domain SID.\n"));
+                       SAFE_FREE(sam_sid);
+                       return NULL;
+               }
+       }
+
+       return sam_sid;
+}
+
+/* return our global_sam_sid */
+struct dom_sid *get_global_sam_sid(void)
+{
+       struct db_context *db;
+
+       if (global_sam_sid != NULL)
+               return global_sam_sid;
 
        /*
-        * Use chmod here as some (strange) UNIX's don't
-        * have fchmod. JRA.
-        */     
-
-       if(chmod(sid_file, 0644) < 0) {
-               DEBUG(0,("unable to set correct permissions on file %s. \
-Error was %s\n", sid_file, strerror(errno) ));
-               do_file_lock( fd, 60, F_UNLCK);
-               close(fd);
-               return False;
-       } 
-       
-       if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
-               DEBUG(0,("unable to write file %s. Error was %s\n",
-                        sid_file, strerror(errno) ));
-               do_file_lock( fd, 60, F_UNLCK);
-               close(fd);
-               return False;
-       } 
-       
-       /*
-        * Unlock & exit.
+        * memory for global_sam_sid is allocated in
+        * pdb_generate_sam_sid() as needed
+        *
+        * Note: this is guarded by a transaction
+        *       to prevent races on startup which
+        *       can happen with some dbwrap backends
         */
-       
-       do_file_lock( fd, 60, F_UNLCK);
-       close(fd);
-       return True;
-}   
 
+       db = secrets_db_ctx();
+       if (!db) {
+               smb_panic("could not open secrets db");
+       }
 
+       if (dbwrap_transaction_start(db) != 0) {
+               smb_panic("could not start transaction on secrets db");
+       }
+
+       if (!(global_sam_sid = pdb_generate_sam_sid())) {
+               dbwrap_transaction_cancel(db);
+               smb_panic("could not generate a machine SID");
+       }
+
+       if (dbwrap_transaction_commit(db) != 0) {
+               smb_panic("could not start commit secrets db");
+       }
+
+       return global_sam_sid;
+}
+
+/**
+ * Force get_global_sam_sid to requery the backends
+ */
+void reset_global_sam_sid(void) 
+{
+       SAFE_FREE(global_sam_sid);
+}
+
+/*****************************************************************
+ Check if the SID is our sam SID (S-1-5-21-x-y-z).
+*****************************************************************/
+
+bool sid_check_is_our_sam(const struct dom_sid *sid)
+{
+       return dom_sid_equal(sid, get_global_sam_sid());
+}
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+
+bool sid_check_is_in_our_sam(const struct dom_sid *sid)
+{
+       struct dom_sid dom_sid;
+
+       sid_copy(&dom_sid, sid);
+       sid_split_rid(&dom_sid, NULL);
+       return sid_check_is_our_sam(&dom_sid);
+}