strchr and strrchr are macros when compiling with optimisation in gcc, so we can...
[samba.git] / source3 / passdb / machine_sid.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password and authentication handling
5    Copyright (C) Jeremy Allison                 1996-1998
6    Copyright (C) Luke Kenneth Casson Leighton   1996-1998
7    Copyright (C) Gerald (Jerry) Carter          2000
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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 /****************************************************************************
27  Read the machine SID from a file.
28 ****************************************************************************/
29
30 static BOOL read_sid_from_file(int fd, char *sid_file)
31 {
32   fstring fline;
33
34   memset(fline, '\0', sizeof(fline));
35
36   if(read(fd, fline, sizeof(fline) -1 ) < 0) {
37     DEBUG(0,("unable to read file %s. Error was %s\n",
38            sid_file, strerror(errno) ));
39     return False;
40   }
41
42   /*
43    * Convert to the machine SID.
44    */
45
46   fline[sizeof(fline)-1] = '\0';
47   if(!string_to_sid( &global_sam_sid, fline)) {
48     DEBUG(0,("unable to generate machine SID.\n"));
49     return False;
50   }
51
52   return True;
53 }
54
55 /****************************************************************************
56  Generate the global machine sid. Look for the MACHINE.SID file first, if
57  not found then look in smb.conf and use it to create the MACHINE.SID file.
58  Note this function will be replaced soon. JRA.
59 ****************************************************************************/
60
61 BOOL pdb_generate_sam_sid(void)
62 {
63         int fd;
64         char *p;
65         pstring sid_file;
66         fstring sid_string;
67         SMB_STRUCT_STAT st;
68         BOOL overwrite_bad_sid = False;
69
70         generate_wellknown_sids();
71
72         pstrcpy(sid_file, lp_smb_passwd_file());
73         p = strrchr_m(sid_file, '/');
74         if(p != NULL) {
75                 *++p = '\0';
76         }
77
78         if (!directory_exist(sid_file, NULL)) {
79                 if (mkdir(sid_file, 0700) != 0) {
80                         DEBUG(0,("can't create private directory %s : %s\n",
81                                  sid_file, strerror(errno)));
82                         return False;
83                 }
84         }
85
86         pstrcat(sid_file, "MACHINE.SID");
87     
88         if((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
89                 DEBUG(0,("unable to open or create file %s. Error was %s\n",
90                          sid_file, strerror(errno) ));
91                 return False;
92         } 
93   
94         /*
95          * Check if the file contains data.
96          */
97         
98         if(sys_fstat( fd, &st) < 0) {
99                 DEBUG(0,("unable to stat file %s. Error was %s\n",
100                          sid_file, strerror(errno) ));
101                 close(fd);
102                 return False;
103         } 
104   
105         if(st.st_size > 0) {
106                 /*
107                  * We have a valid SID - read it.
108                  */
109                 if(!read_sid_from_file( fd, sid_file)) {
110                         DEBUG(0,("unable to read file %s. Error was %s\n",
111                                  sid_file, strerror(errno) ));
112                         close(fd);
113                         return False;
114                 }
115
116                 /*
117                  * JRA. Reversed the sense of this test now that I have
118                  * actually done this test *personally*. One more reason
119                  * to never trust third party information you have not
120                  * independently verified.... sigh. JRA.
121                  */
122
123                 if(global_sam_sid.num_auths > 0 && global_sam_sid.sub_auths[0] == 0x21) {
124                         /*
125                          * Fix and re-write...
126                          */
127                         overwrite_bad_sid = True;
128                         global_sam_sid.sub_auths[0] = 21;
129                         DEBUG(5,("pdb_generate_sam_sid: Old (incorrect) sid id_auth of hex 21 \
130 detected - re-writing to be decimal 21 instead.\n" ));
131                         sid_to_string(sid_string, &global_sam_sid);
132                         if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) {
133                                 DEBUG(0,("unable to seek file file %s. Error was %s\n",
134                                          sid_file, strerror(errno) ));
135                                 close(fd);
136                                 return False;
137                         }
138                 } else {
139                         close(fd);
140                         return True;
141                 }
142         } else {
143                 /*
144                  * The file contains no data - we need to generate our
145                  * own sid.
146                  * Generate the new sid data & turn it into a string.
147                  */
148                 int i;
149                 uchar raw_sid_data[12];
150                 DOM_SID mysid;
151
152                 memset((char *)&mysid, '\0', sizeof(DOM_SID));
153                 mysid.sid_rev_num = 1;
154                 mysid.id_auth[5] = 5;
155                 mysid.num_auths = 0;
156                 mysid.sub_auths[mysid.num_auths++] = 21;
157
158                 generate_random_buffer( raw_sid_data, 12, True);
159                 for( i = 0; i < 3; i++)
160                         mysid.sub_auths[mysid.num_auths++] = IVAL(raw_sid_data, i*4);
161
162                 sid_to_string(sid_string, &mysid);
163         } 
164         
165         fstrcat(sid_string, "\n");
166         
167         /*
168          * Ensure our new SID is valid.
169          */
170         
171         if(!string_to_sid( &global_sam_sid, sid_string)) {
172                 DEBUG(0,("unable to generate machine SID.\n"));
173                 return False;
174         } 
175   
176         /*
177          * Do an exclusive blocking lock on the file.
178          */
179         
180         if(!do_file_lock( fd, 60, F_WRLCK)) {
181                 DEBUG(0,("unable to lock file %s. Error was %s\n",
182                          sid_file, strerror(errno) ));
183                 close(fd);
184                 return False;
185         } 
186  
187         if(!overwrite_bad_sid) {
188                 /*
189                  * At this point we have a blocking lock on the SID
190                  * file - check if in the meantime someone else wrote
191                  * SID data into the file. If so - they were here first,
192                  * use their data.
193                  */
194         
195                 if(sys_fstat( fd, &st) < 0) {
196                         DEBUG(0,("unable to stat file %s. Error was %s\n",
197                                  sid_file, strerror(errno) ));
198                         close(fd);
199                         return False;
200                 } 
201   
202                 if(st.st_size > 0) {
203                         /*
204                          * Unlock as soon as possible to reduce
205                          * contention on the exclusive lock.
206                          */ 
207                         do_file_lock( fd, 60, F_UNLCK);
208                 
209                         /*
210                          * We have a valid SID - read it.
211                          */
212                 
213                         if(!read_sid_from_file( fd, sid_file)) {
214                                 DEBUG(0,("unable to read file %s. Error was %s\n",
215                                          sid_file, strerror(errno) ));
216                                 close(fd);
217                                 return False;
218                         }
219                         close(fd);
220                         return True;
221                 } 
222         }
223         
224         /*
225          * The file is still empty and we have an exlusive lock on it,
226          * or we're fixing an earlier mistake.
227          * Write out out SID data into the file.
228          */
229
230         /*
231          * Use chmod here as some (strange) UNIX's don't
232          * have fchmod. JRA.
233          */     
234
235         if(chmod(sid_file, 0644) < 0) {
236                 DEBUG(0,("unable to set correct permissions on file %s. \
237 Error was %s\n", sid_file, strerror(errno) ));
238                 do_file_lock( fd, 60, F_UNLCK);
239                 close(fd);
240                 return False;
241         } 
242         
243         if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
244                 DEBUG(0,("unable to write file %s. Error was %s\n",
245                          sid_file, strerror(errno) ));
246                 do_file_lock( fd, 60, F_UNLCK);
247                 close(fd);
248                 return False;
249         } 
250         
251         /*
252          * Unlock & exit.
253          */
254         
255         do_file_lock( fd, 60, F_UNLCK);
256         close(fd);
257         return True;
258 }   
259
260