Line data Source code
1 : /* 2 : Unix SMB/CIFS implementation. 3 : Password and authentication handling 4 : Copyright (C) Jeremy Allison 1996-2002 5 : Copyright (C) Andrew Tridgell 2002 6 : Copyright (C) Gerald (Jerry) Carter 2000 7 : Copyright (C) Stefan (metze) Metzmacher 2002 8 : 9 : This program is free software; you can redistribute it and/or modify 10 : it under the terms of the GNU General Public License as published by 11 : the Free Software Foundation; either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : This program is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU General Public License for more details. 18 : 19 : You should have received a copy of the GNU General Public License 20 : along with this program. If not, see <http://www.gnu.org/licenses/>. 21 : */ 22 : 23 : #include "includes.h" 24 : #include "passdb/machine_sid.h" 25 : #include "secrets.h" 26 : #include "dbwrap/dbwrap.h" 27 : #include "../libcli/security/security.h" 28 : 29 : /* NOTE! the global_sam_sid is the SID of our local SAM. This is only 30 : equal to the domain SID when we are a DC, otherwise its our 31 : workstation SID */ 32 : static struct dom_sid *global_sam_sid=NULL; 33 : 34 : #undef DBGC_CLASS 35 : #define DBGC_CLASS DBGC_PASSDB 36 : 37 : /**************************************************************************** 38 : Read a SID from a file. This is for compatibility with the old MACHINE.SID 39 : style of SID storage 40 : ****************************************************************************/ 41 : 42 20 : static bool read_sid_from_file(const char *fname, struct dom_sid *sid) 43 : { 44 20 : char *line = NULL; 45 2 : size_t n; 46 2 : ssize_t len; 47 20 : bool ret = false; 48 20 : FILE *f = NULL; 49 : 50 20 : f = fopen(fname, "r"); 51 20 : if (f == NULL) { 52 18 : return false; 53 : } 54 : 55 0 : len = getline(&line, &n, f); 56 0 : if (len >= 0) { 57 0 : ret = string_to_sid(sid, line); 58 0 : SAFE_FREE(line); 59 : } 60 : 61 0 : fclose(f); 62 0 : return ret; 63 : } 64 : 65 : /* 66 : generate a random sid - used to build our own sid if we don't have one 67 : */ 68 20 : static void generate_random_sid(struct dom_sid *sid) 69 : { 70 2 : int i; 71 2 : uchar raw_sid_data[12]; 72 : 73 20 : *sid = (struct dom_sid) { 74 : .sid_rev_num = 1, 75 : .id_auth[5] = 5, 76 : }; 77 : 78 20 : sid->sub_auths[sid->num_auths++] = 21; 79 : 80 20 : generate_random_buffer(raw_sid_data, 12); 81 82 : for (i = 0; i < 3; i++) 82 60 : sid->sub_auths[sid->num_auths++] = IVAL(raw_sid_data, i*4); 83 20 : } 84 : 85 : /**************************************************************************** 86 : Generate the global machine sid. 87 : ****************************************************************************/ 88 : 89 1681 : static struct dom_sid *pdb_generate_sam_sid(void) 90 : { 91 17 : struct dom_sid domain_sid; 92 1681 : char *fname = NULL; 93 17 : struct dom_sid *sam_sid; 94 : 95 1681 : if(!(sam_sid=SMB_MALLOC_P(struct dom_sid))) 96 0 : return NULL; 97 : 98 1681 : if ( IS_DC ) { 99 812 : if (secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { 100 797 : sid_copy(sam_sid, &domain_sid); 101 797 : return sam_sid; 102 : } 103 : } 104 : 105 884 : if (secrets_fetch_domain_sid(lp_netbios_name(), sam_sid)) { 106 : 107 : /* We got our sid. If not a pdc/bdc, we're done. */ 108 864 : if ( !IS_DC ) 109 847 : return sam_sid; 110 : 111 15 : if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { 112 : 113 : /* No domain sid and we're a pdc/bdc. Store it */ 114 : 115 15 : if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) { 116 0 : DEBUG(0,("pdb_generate_sam_sid: Can't store domain SID as a pdc/bdc.\n")); 117 0 : SAFE_FREE(sam_sid); 118 0 : return NULL; 119 : } 120 14 : return sam_sid; 121 : } 122 : 123 0 : if (!dom_sid_equal(&domain_sid, sam_sid)) { 124 : 125 : /* Domain name sid doesn't match global sam sid. Re-store domain sid as 'local' sid. */ 126 : 127 0 : DEBUG(0,("pdb_generate_sam_sid: Mismatched SIDs as a pdc/bdc.\n")); 128 0 : if (!secrets_store_domain_sid(lp_netbios_name(), &domain_sid)) { 129 0 : DEBUG(0,("pdb_generate_sam_sid: Can't re-store domain SID for local sid as PDC/BDC.\n")); 130 0 : SAFE_FREE(sam_sid); 131 0 : return NULL; 132 : } 133 0 : return sam_sid; 134 : } 135 : 136 0 : return sam_sid; 137 : } 138 : 139 : /* check for an old MACHINE.SID file for backwards compatibility */ 140 20 : if (asprintf(&fname, "%s/MACHINE.SID", lp_private_dir()) == -1) { 141 0 : SAFE_FREE(sam_sid); 142 0 : return NULL; 143 : } 144 : 145 20 : if (read_sid_from_file(fname, sam_sid)) { 146 : /* remember it for future reference and unlink the old MACHINE.SID */ 147 0 : if (!secrets_store_domain_sid(lp_netbios_name(), sam_sid)) { 148 0 : DEBUG(0,("pdb_generate_sam_sid: Failed to store SID from file.\n")); 149 0 : SAFE_FREE(fname); 150 0 : SAFE_FREE(sam_sid); 151 0 : return NULL; 152 : } 153 0 : unlink(fname); 154 0 : if ( !IS_DC ) { 155 0 : if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) { 156 0 : DEBUG(0,("pdb_generate_sam_sid: Failed to store domain SID from file.\n")); 157 0 : SAFE_FREE(fname); 158 0 : SAFE_FREE(sam_sid); 159 0 : return NULL; 160 : } 161 : } 162 : 163 : /* Stored the old sid from MACHINE.SID successfully.*/ 164 0 : SAFE_FREE(fname); 165 0 : return sam_sid; 166 : } 167 : 168 20 : SAFE_FREE(fname); 169 : 170 : /* we don't have the SID in secrets.tdb, we will need to 171 : generate one and save it */ 172 20 : generate_random_sid(sam_sid); 173 : 174 20 : if (!secrets_store_domain_sid(lp_netbios_name(), sam_sid)) { 175 0 : DEBUG(0,("pdb_generate_sam_sid: Failed to store generated machine SID.\n")); 176 0 : SAFE_FREE(sam_sid); 177 0 : return NULL; 178 : } 179 20 : if ( IS_DC ) { 180 0 : if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) { 181 0 : DEBUG(0,("pdb_generate_sam_sid: Failed to store generated domain SID.\n")); 182 0 : SAFE_FREE(sam_sid); 183 0 : return NULL; 184 : } 185 : } 186 : 187 18 : return sam_sid; 188 : } 189 : 190 : /* return our global_sam_sid */ 191 691434 : struct dom_sid *get_global_sam_sid(void) 192 : { 193 1536 : struct db_context *db; 194 : 195 691434 : if (global_sam_sid != NULL) 196 688234 : return global_sam_sid; 197 : 198 : /* 199 : * memory for global_sam_sid is allocated in 200 : * pdb_generate_sam_sid() as needed 201 : * 202 : * Note: this is guarded by a transaction 203 : * to prevent races on startup which 204 : * can happen with some dbwrap backends 205 : */ 206 : 207 1681 : db = secrets_db_ctx(); 208 1681 : if (!db) { 209 0 : smb_panic("could not open secrets db"); 210 : } 211 : 212 1681 : if (dbwrap_transaction_start(db) != 0) { 213 0 : smb_panic("could not start transaction on secrets db"); 214 : } 215 : 216 1681 : if (!(global_sam_sid = pdb_generate_sam_sid())) { 217 0 : dbwrap_transaction_cancel(db); 218 0 : smb_panic("could not generate a machine SID"); 219 : } 220 : 221 1681 : if (dbwrap_transaction_commit(db) != 0) { 222 0 : smb_panic("could not start commit secrets db"); 223 : } 224 : 225 1681 : return global_sam_sid; 226 : } 227 : 228 : /** 229 : * Force get_global_sam_sid to requery the backends 230 : */ 231 487 : void reset_global_sam_sid(void) 232 : { 233 487 : SAFE_FREE(global_sam_sid); 234 487 : } 235 : 236 : /***************************************************************** 237 : Check if the SID is our sam SID (S-1-5-21-x-y-z). 238 : *****************************************************************/ 239 : 240 203315 : bool sid_check_is_our_sam(const struct dom_sid *sid) 241 : { 242 203315 : return dom_sid_equal(sid, get_global_sam_sid()); 243 : } 244 : 245 : /***************************************************************** 246 : Check if the SID is our domain SID (S-1-5-21-x-y-z). 247 : *****************************************************************/ 248 : 249 129510 : bool sid_check_is_in_our_sam(const struct dom_sid *sid) 250 : { 251 325 : struct dom_sid dom_sid; 252 : 253 129510 : sid_copy(&dom_sid, sid); 254 129510 : sid_split_rid(&dom_sid, NULL); 255 129510 : return sid_check_is_our_sam(&dom_sid); 256 : }