Fix some nonempty blank lines
[ira/wip.git] / source3 / passdb / machine_sid.c
index 34b0c742087267ff998dc9a5151d7eb09c3f8470..c7c3cc474b9dcb213036191fa1b716e0ceb2d1d4 100644 (file)
@@ -1,14 +1,14 @@
 /* 
-   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,
    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"
 
+/* 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 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, DOM_SID *sid)
 {
-  fstring fline;
-
-  memset(fline, '\0', sizeof(fline));
+       char **lines;
+       int numlines;
+       bool ret;
 
-  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;
-  }
-
-  /*
-   * Convert to the machine SID.
-   */
-
-  fline[sizeof(fline)-1] = '\0';
-  if(!string_to_sid( &global_sam_sid, fline)) {
-    DEBUG(0,("unable to generate machine SID.\n"));
-    return False;
-  }
+       lines = file_lines_load(fname, &numlines,0, NULL);
+       
+       if (!lines || numlines < 1) {
+               if (lines) TALLOC_FREE(lines);
+               return False;
+       }
+       
+       ret = string_to_sid(sid, lines[0]);
+       TALLOC_FREE(lines);
+       return ret;
+}
 
-  return True;
+/*
+  generate a random sid - used to build our own sid if we don't have one
+*/
+static void generate_random_sid(DOM_SID *sid)
+{
+       int i;
+       uchar raw_sid_data[12];
+
+       memset((char *)sid, '\0', sizeof(*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 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';
-       }
+       DOM_SID domain_sid;
+       char *fname = NULL;
+       DOM_SID *sam_sid;
+       
+       if(!(sam_sid=SMB_MALLOC_P(DOM_SID)))
+               return NULL;
 
-       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 ( 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(global_myname(), 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 (!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(global_myname(), &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.
-                        */
+
+               return sam_sid;
                
-                       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;
+       }
+
+       /* 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(global_myname(), 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.
-        */
 
-       /*
-        * 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;
-       } 
+       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(global_myname(), 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 */
+DOM_SID *get_global_sam_sid(void)
+{
+       struct db_context *db;
+
+       if (global_sam_sid != NULL)
+               return global_sam_sid;
        
        /*
-        * Unlock & exit.
+        * memory for global_sam_sid is allocated in
+        * pdb_generate_sam_sid() as needed
+        *
+        * Note: this is garded 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 (db->transaction_start(db) != 0) {
+               smb_panic("could not start transaction on secrets db");
+       }
+
+       if (!(global_sam_sid = pdb_generate_sam_sid())) {
+               db->transaction_cancel(db);
+               smb_panic("could not generate a machine SID");
+       }
 
+       if (db->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 domain SID (S-1-5-21-x-y-z).
+*****************************************************************/  
+
+bool sid_check_is_domain(const DOM_SID *sid)
+{
+       return 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_domain(const DOM_SID *sid)
+{
+       DOM_SID dom_sid;
+       uint32 rid;
+
+       sid_copy(&dom_sid, sid);
+       sid_split_rid(&dom_sid, &rid);
+       return sid_check_is_domain(&dom_sid);
+}