windows-afssw-20080806
[openafs.git] / src / WINNT / afsreg / afssw.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #include <shlobj.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stddef.h>
18 #include <string.h>
19 #include <errno.h>
20
21 #include <afs/errmap_nt.h>
22
23 #include "afsreg.h"
24 #include "afssw.h"
25
26 static int
27 StringDataRead(const char *keyName, const char *valueName, char **bufPP);
28
29 static int
30 StringDataWrite(const char *keyName, const char *valueName, const char *data);
31
32 static int
33 DwordDataRead(const char *keyName, const char *valueName, DWORD *data);
34
35
36
37 /* Functions for accessing AFS software configuration information. */
38
39 /*
40  * afssw_GetServerInstallDir() -- Get directory in which AFS server software is
41  *     installed.  Sets *bufPP to point to allocated buffer containing string.
42  *
43  * RETURN CODES: 0 success, -1 failed (errno set)
44  */
45 int
46 afssw_GetServerInstallDir(char **bufPP)  /* [out] data buffer */
47 {
48     return StringDataRead(AFSREG_SVR_SW_VERSION_KEY,
49                           AFSREG_SVR_SW_VERSION_DIR_VALUE,
50                           bufPP);
51 }
52
53
54 /*
55  * afssw_GetClientInstallDir() -- Get directory in which AFS client software is
56  *     installed.  Sets *bufPP to point to allocated buffer containing string.
57  *
58  * RETURN CODES: 0 success, -1 failed (errno set)
59  */
60 int
61 afssw_GetClientInstallDir(char **bufPP)   /* [out] data buffer */
62 {
63     int retval = StringDataRead(AFSREG_CLT_SW_VERSION_KEY,
64                           AFSREG_CLT_SW_VERSION_DIR_VALUE,
65                           bufPP);
66     if (retval)
67         retval = StringDataRead(AFSREG_CLT_TOOLS_SW_VERSION_KEY,
68                           AFSREG_CLT_SW_VERSION_DIR_VALUE,
69                           bufPP);
70     return retval;
71 }
72
73 /*
74  * afssw_GetClientCellServDBDir() -- Get directory in which AFS client CellServDB
75  * file is installed.  Sets *bufPP to point to allocated buffer containing string.
76  *
77  * RETURN CODES: 0 success, -1 failed (errno set)
78  */
79 int
80 afssw_GetClientCellServDBDir(char **bufPP)   /* [out] data buffer */
81 {
82     char wdir[512];
83     int tlen;
84     char *path = NULL;
85     DWORD cbPath;
86
87     cbPath = GetEnvironmentVariable("AFSCONF", NULL, 0);
88     if (cbPath) {
89         cbPath += 2;
90         path = malloc(cbPath);
91         if (path) {
92             GetEnvironmentVariable("AFSCONF", path, cbPath);
93             tlen = (int)strlen(path);
94             if (path[tlen-1] != '\\') {
95                 strncat(path, "\\", cbPath);
96                 path[cbPath-1] = '\0';
97             }
98             *bufPP = path;
99             return 0;
100         }
101     }
102
103     if (!StringDataRead(AFSREG_CLT_OPENAFS_KEY,
104                           AFSREG_CLT_OPENAFS_CELLSERVDB_DIR_VALUE,
105                          &path)) {
106         tlen = (int)strlen(path);
107         if (path[tlen-1] != '\\') {
108             char * newPath = malloc(tlen+2);
109             if (newPath) {
110                 snprintf(newPath,tlen+2,"%s\\",path);
111                 free(path);
112                 path = newPath;
113             }
114         }
115         *bufPP = path;
116         return 0;
117     }
118
119     /*
120      * Try to find the All Users\Application Data\OpenAFS\Client directory.
121      * If it exists and it contains a CellServDB file, return that. 
122      * Otherwise, return the Install Directory for backward compatibility.
123      * SHGetFolderPath requires wdir to be of length MAX_PATH which is 260.
124      */
125     if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 
126                                     SHGFP_TYPE_CURRENT, wdir)))
127     {   HANDLE fh;
128
129         tlen = (int)strlen(wdir);
130         if (wdir[tlen-1] != '\\') {
131             strncat(wdir, "\\", sizeof(wdir));
132             wdir[sizeof(wdir)-1] = '\0';
133             tlen++;
134         }
135         strncat(wdir, "OpenAFS\\Client\\CellServDB", sizeof(wdir)); 
136         wdir[sizeof(wdir)-1] = '\0';
137
138         fh = CreateFile(wdir, GENERIC_READ, FILE_SHARE_READ, NULL, 
139                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
140         if (fh != INVALID_HANDLE_VALUE) {
141             CloseHandle(fh);
142             tlen += (int)strlen("OpenAFS\\Client\\");
143             wdir[tlen] = '\0';
144             *bufPP = strdup(wdir);
145             return 0;
146         }
147     }
148
149     return afssw_GetClientInstallDir(bufPP);
150 }
151
152
153 /*
154  * afssw_GetClientCellName() -- Get name of cell in which AFS client is
155  *     configured.  Sets *bufPP to point to allocated buffer containing string.
156  *
157  * RETURN CODES: 0 success, -1 failed (errno set)
158  */
159 int
160 afssw_GetClientCellName(char **bufPP)  /* [out] data buffer */
161 {
162     return StringDataRead(AFSREG_CLT_SVC_PARAM_KEY,
163                           AFSREG_CLT_SVC_PARAM_CELL_VALUE,
164                           bufPP);
165 }
166
167
168 /*
169  * afssw_SetClientCellName() -- Set name of cell in which AFS client is
170  *     configured.
171  *
172  * RETURN CODES: 0 success, -1 failed (errno set)
173  */
174 int
175 afssw_SetClientCellName(const char *cellName)
176 {
177     return StringDataWrite(AFSREG_CLT_SVC_PARAM_KEY,
178                            AFSREG_CLT_SVC_PARAM_CELL_VALUE,
179                            cellName);
180 }
181
182
183 /*
184  * afssw_GetServerVersion() -- Get version number of installed server.
185  *
186  * RETURN CODES: 0 success, -1 failed (errno set)
187  */
188 int
189 afssw_GetServerVersion(unsigned *major,  /* major version number */
190                        unsigned *minor,  /* minor version number */
191                        unsigned *patch)  /* patch level */
192 {
193     DWORD dwMajor, dwMinor, dwPatch;
194
195     if (DwordDataRead(AFSREG_SVR_SW_VERSION_KEY,
196                       AFSREG_SVR_SW_VERSION_MAJOR_VALUE,
197                       &dwMajor) ||
198
199         DwordDataRead(AFSREG_SVR_SW_VERSION_KEY,
200                       AFSREG_SVR_SW_VERSION_MINOR_VALUE,
201                       &dwMinor) ||
202
203         DwordDataRead(AFSREG_SVR_SW_VERSION_KEY,
204                       AFSREG_SVR_SW_VERSION_PATCH_VALUE,
205                       &dwPatch)) {
206         /* a read failed */
207         return -1;
208     } else {
209         /* return values */
210         *major = dwMajor;
211         *minor = dwMinor;
212         *patch = dwPatch;
213         return 0;
214     }
215 }
216
217
218 /*
219  * afssw_GetClientVersion() -- Get version number of installed client.
220  *
221  * RETURN CODES: 0 success, -1 failed (errno set)
222  */
223 int
224 afssw_GetClientVersion(unsigned *major,  /* major version number */
225                        unsigned *minor,  /* minor version number */
226                        unsigned *patch)  /* patch level */
227 {
228     DWORD dwMajor, dwMinor, dwPatch;
229
230     if (DwordDataRead(AFSREG_CLT_SW_VERSION_KEY,
231                       AFSREG_CLT_SW_VERSION_MAJOR_VALUE,
232                       &dwMajor) ||
233
234         DwordDataRead(AFSREG_CLT_SW_VERSION_KEY,
235                       AFSREG_CLT_SW_VERSION_MINOR_VALUE,
236                       &dwMinor) ||
237
238         DwordDataRead(AFSREG_CLT_SW_VERSION_KEY,
239                       AFSREG_CLT_SW_VERSION_PATCH_VALUE,
240                       &dwPatch)) {
241         /* a read failed */
242         return -1;
243     } else {
244         /* return values */
245         *major = dwMajor;
246         *minor = dwMinor;
247         *patch = dwPatch;
248         return 0;
249     }
250 }
251
252
253
254
255 /* ----------------------- local functions ------------------------- */
256
257 /*
258  * StringDataRead() -- read registry data of type REG_SZ and return in
259  *     allocated buffer.
260  *
261  * RETURN CODES: 0 success, -1 failed (errno set)
262  */
263 static int
264 StringDataRead(const char *keyName, const char *valueName, char **bufPP)
265 {
266     long status;
267     HKEY key;
268
269     if (bufPP == NULL) {
270         errno = EINVAL;
271         return -1;
272     }
273
274     status = RegOpenKeyAlt(AFSREG_NULL_KEY, keyName, KEY_READ, 0, &key, NULL);
275
276     if (status == ERROR_SUCCESS) {
277         DWORD dataType;
278         char *dataBuf = NULL;
279
280         status = RegQueryValueAlt(key, valueName, &dataType, &dataBuf, NULL);
281
282         if (status == ERROR_SUCCESS) {
283             if (dataType == REG_SZ) {
284                 *bufPP = dataBuf;
285             } else {
286                 /* invalid data type */
287                 free(dataBuf);
288                 status = ERROR_INVALID_DATA;
289             }
290         }
291         (void)RegCloseKey(key);
292     }
293
294     if (status) {
295         errno = nterr_nt2unix(status, EIO);
296         return -1;
297     }
298     return 0;
299 }
300
301
302 /*
303  * StringDataWrite() -- write registry data of type REG_SZ.
304  * 
305  * RETURN CODES: 0 success, -1 failed (errno set)
306  */
307 static int
308 StringDataWrite(const char *keyName, const char *valueName, const char *data)
309 {
310     long status;
311     HKEY key;
312
313     if (data == NULL) {
314         errno = EINVAL;
315         return -1;
316     }
317
318     status = RegOpenKeyAlt(AFSREG_NULL_KEY,
319                            keyName, KEY_WRITE, 1 /* create */, &key, NULL);
320
321     if (status == ERROR_SUCCESS) {
322         status = RegSetValueEx(key,
323                                valueName,
324                                0, REG_SZ, data, (DWORD)strlen(data) + 1);
325
326         (void)RegCloseKey(key);
327     }
328
329     if (status) {
330         errno = nterr_nt2unix(status, EIO);
331         return -1;
332     }
333     return 0;
334 }
335
336
337 /*
338  * DwordDataRead() -- read registry data of type REG_DWORD.
339  *
340  * RETURN CODES: 0 success, -1 failed (errno set)
341  */
342 static int
343 DwordDataRead(const char *keyName, const char *valueName, DWORD *data)
344 {
345     long status;
346     HKEY key;
347
348     status = RegOpenKeyAlt(AFSREG_NULL_KEY, keyName, KEY_READ, 0, &key, NULL);
349
350     if (status == ERROR_SUCCESS) {
351         DWORD dataType;
352         DWORD dataBuf;
353         DWORD dataSize = sizeof(DWORD);
354
355         status = RegQueryValueEx(key, valueName,
356                                  NULL, &dataType, (void *)&dataBuf, &dataSize);
357
358         if (status == ERROR_SUCCESS) {
359             if (dataType == REG_DWORD) {
360                 *data = dataBuf;
361             } else {
362                 /* invalid data type */
363                 status = ERROR_INVALID_DATA;
364             }
365         }
366         (void)RegCloseKey(key);
367     }
368
369     if (status) {
370         errno = nterr_nt2unix(status, EIO);
371         return -1;
372     }
373     return 0;
374 }