2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
25 #define SECURITY_WIN32
36 #include <cm_scache.h>
42 #include <pioctl_nt.h>
43 #include <WINNT/afsreg.h>
44 #include <lanahelper.h>
46 #include <loadfuncs-krb5.h>
49 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
51 #define FS_IOCTLREQUEST_MAXSIZE 8192
52 /* big structure for representing and storing an IOCTL request */
53 typedef struct fs_ioctlRequest {
54 char *mp; /* marshalling/unmarshalling ptr */
55 long nbytes; /* bytes received (when unmarshalling) */
56 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
60 CMtoUNIXerror(int cm_code)
63 case CM_ERROR_TIMEDOUT:
65 case CM_ERROR_NOACCESS:
67 case CM_ERROR_NOSUCHFILE:
75 case CM_ERROR_CROSSDEVLINK:
81 case CM_ERROR_READONLY:
83 case CM_ERROR_WOULDBLOCK:
85 case CM_ERROR_NOSUCHCELL:
86 return ESRCH; /* hack */
87 case CM_ERROR_NOSUCHVOLUME:
88 return EPIPE; /* hack */
89 case CM_ERROR_NOMORETOKENS:
90 return EDOM; /* hack */
91 case CM_ERROR_TOOMANYBUFS:
92 return EFBIG; /* hack */
99 InitFSRequest(fs_ioctlRequest_t * rp)
109 static BOOL debug = 0;
114 if (RegOpenKey (HKEY_LOCAL_MACHINE,
115 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
117 DWORD dwSize = sizeof(BOOL);
118 DWORD dwType = REG_DWORD;
119 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
131 DECL_FUNC_PTR(krb5_cc_default_name);
132 DECL_FUNC_PTR(krb5_cc_set_default_name);
133 DECL_FUNC_PTR(krb5_get_default_config_files);
134 DECL_FUNC_PTR(krb5_free_config_files);
135 DECL_FUNC_PTR(krb5_free_context);
136 DECL_FUNC_PTR(krb5_get_default_realm);
137 DECL_FUNC_PTR(krb5_free_default_realm);
138 DECL_FUNC_PTR(krb5_init_context);
139 DECL_FUNC_PTR(krb5_cc_default);
140 DECL_FUNC_PTR(krb5_parse_name);
141 DECL_FUNC_PTR(krb5_free_principal);
142 DECL_FUNC_PTR(krb5_cc_close);
143 DECL_FUNC_PTR(krb5_cc_get_principal);
144 DECL_FUNC_PTR(krb5_build_principal);
145 DECL_FUNC_PTR(krb5_c_random_make_octets);
146 DECL_FUNC_PTR(krb5_get_init_creds_password);
147 DECL_FUNC_PTR(krb5_free_cred_contents);
148 DECL_FUNC_PTR(krb5_cc_resolve);
149 DECL_FUNC_PTR(krb5_unparse_name);
150 DECL_FUNC_PTR(krb5_free_unparsed_name);
152 FUNC_INFO krb5_fi[] = {
153 MAKE_FUNC_INFO(krb5_cc_default_name),
154 MAKE_FUNC_INFO(krb5_cc_set_default_name),
155 MAKE_FUNC_INFO(krb5_get_default_config_files),
156 MAKE_FUNC_INFO(krb5_free_config_files),
157 MAKE_FUNC_INFO(krb5_free_context),
158 MAKE_FUNC_INFO(krb5_get_default_realm),
159 MAKE_FUNC_INFO(krb5_free_default_realm),
160 MAKE_FUNC_INFO(krb5_init_context),
161 MAKE_FUNC_INFO(krb5_cc_default),
162 MAKE_FUNC_INFO(krb5_parse_name),
163 MAKE_FUNC_INFO(krb5_free_principal),
164 MAKE_FUNC_INFO(krb5_cc_close),
165 MAKE_FUNC_INFO(krb5_cc_get_principal),
166 MAKE_FUNC_INFO(krb5_build_principal),
167 MAKE_FUNC_INFO(krb5_c_random_make_octets),
168 MAKE_FUNC_INFO(krb5_get_init_creds_password),
169 MAKE_FUNC_INFO(krb5_free_cred_contents),
170 MAKE_FUNC_INFO(krb5_cc_resolve),
171 MAKE_FUNC_INFO(krb5_unparse_name),
172 MAKE_FUNC_INFO(krb5_free_unparsed_name),
178 const char* dll_name,
180 HINSTANCE* ph, // [out, optional] - DLL handle
181 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
182 int cleanup, // cleanup function pointers and unload on error
183 int go_on, // continue loading even if some functions cannot be loaded
184 int silent // do not pop-up a system dialog if DLL cannot be loaded
193 if (pindex) *pindex = -1;
195 for (n = 0; fi[n].func_ptr_var; n++)
196 *(fi[n].func_ptr_var) = 0;
199 em = SetErrorMode(SEM_FAILCRITICALERRORS);
200 h = LoadLibrary(dll_name);
208 for (i = 0; (go_on || !error) && (i < n); i++)
210 void* p = (void*)GetProcAddress(h, fi[i].func_name);
216 *(fi[i].func_ptr_var) = p;
219 if (pindex) *pindex = last_i;
220 if (error && cleanup && !go_on) {
221 for (i = 0; i < n; i++) {
222 *(fi[i].func_ptr_var) = 0;
232 #define KERB5DLL "krb5_32.dll"
236 static HINSTANCE hKrb5DLL = 0;
241 hKrb5DLL = LoadLibrary(KERB5DLL);
243 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0))
245 FreeLibrary(hKrb5DLL);
254 GetLSAPrincipalName(char * szUser, DWORD *dwSize)
256 krb5_context ctx = 0;
257 krb5_error_code code;
258 krb5_ccache mslsa_ccache=0;
259 krb5_principal princ = 0;
263 if (!IsKrb5Available())
266 if (code = pkrb5_init_context(&ctx))
269 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
272 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
275 if (code = pkrb5_unparse_name(ctx, princ, &pname))
278 if ( strlen(pname) < *dwSize ) {
279 strncpy(szUser, pname, *dwSize);
280 szUser[*dwSize-1] = '\0';
283 *dwSize = strlen(pname);
287 pkrb5_free_unparsed_name(ctx, pname);
290 pkrb5_free_principal(ctx, princ);
293 pkrb5_cc_close(ctx, mslsa_ccache);
296 pkrb5_free_context(ctx);
301 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
304 char netbiosName[MAX_NB_NAME_LENGTH];
305 char tbuffer[256]="";
308 char szUser[128] = "";
309 char szClient[MAX_PATH] = "";
310 char szPath[MAX_PATH] = "";
313 DWORD ioctlDebug = IoctlDebug();
315 DWORD dwSize = sizeof(szUser);
318 drivep = strchr(fileNamep, ':');
319 if (drivep && (drivep - fileNamep) >= 1) {
320 tbuffer[0] = *(drivep - 1);
322 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
323 } else if (fileNamep[0] == fileNamep[1] &&
324 fileNamep[0] == '\\')
326 int count = 0, i = 0;
328 while (count < 4 && fileNamep[i]) {
329 tbuffer[i] = fileNamep[i];
330 if ( tbuffer[i++] == '\\' )
333 if (fileNamep[i] == 0)
336 strcat(tbuffer, SMB_IOCTL_FILENAME);
340 GetCurrentDirectory(sizeof(curdir), curdir);
341 if ( curdir[1] == ':' ) {
342 tbuffer[0] = curdir[0];
344 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
345 } else if (curdir[0] == curdir[1] &&
348 int count = 0, i = 0;
350 while (count < 4 && curdir[i]) {
351 tbuffer[i] = curdir[i];
352 if ( tbuffer[i++] == '\\' )
358 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
363 /* No file name starting with drive colon specified, use UNC name */
364 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
365 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
369 /* now open the file */
370 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
371 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
372 FILE_FLAG_WRITE_THROUGH, NULL);
374 if (fh == INVALID_HANDLE_VALUE) {
377 gle = GetLastError();
378 if (gle && ioctlDebug ) {
381 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
384 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
390 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
395 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
397 if (RegOpenKey (HKEY_CURRENT_USER,
398 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
400 DWORD dwType = REG_SZ;
401 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
407 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
409 sprintf(szPath, "\\\\%s", szClient);
410 memset (&nr, 0x00, sizeof(NETRESOURCE));
411 nr.dwType=RESOURCETYPE_DISK;
413 nr.lpRemoteName=szPath;
414 res = WNetAddConnection2(&nr,NULL,szUser,0);
417 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
423 sprintf(szPath, "\\\\%s\\all", szClient);
424 res = WNetAddConnection2(&nr,NULL,szUser,0);
427 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
434 goto try_lsa_principal;
436 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
437 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
438 FILE_FLAG_WRITE_THROUGH, NULL);
440 if (fh == INVALID_HANDLE_VALUE) {
441 gle = GetLastError();
442 if (gle && ioctlDebug ) {
445 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
448 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
454 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
463 if (fh == INVALID_HANDLE_VALUE) {
466 dwSize = sizeof(szUser);
467 if (GetLSAPrincipalName(szUser, &dwSize)) {
469 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
471 sprintf(szPath, "\\\\%s", szClient);
472 memset (&nr, 0x00, sizeof(NETRESOURCE));
473 nr.dwType=RESOURCETYPE_DISK;
475 nr.lpRemoteName=szPath;
476 res = WNetAddConnection2(&nr,NULL,szUser,0);
479 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
485 sprintf(szPath, "\\\\%s\\all", szClient);
486 res = WNetAddConnection2(&nr,NULL,szUser,0);
489 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
498 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
499 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
500 FILE_FLAG_WRITE_THROUGH, NULL);
502 if (fh == INVALID_HANDLE_VALUE) {
503 gle = GetLastError();
504 if (gle && ioctlDebug ) {
507 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
510 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
516 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
525 if ( fh == INVALID_HANDLE_VALUE ) {
526 dwSize = sizeof(szUser);
527 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
529 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
531 sprintf(szPath, "\\\\%s", szClient);
532 memset (&nr, 0x00, sizeof(NETRESOURCE));
533 nr.dwType=RESOURCETYPE_DISK;
535 nr.lpRemoteName=szPath;
536 res = WNetAddConnection2(&nr,NULL,szUser,0);
539 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
544 sprintf(szPath, "\\\\%s\\all", szClient);
545 res = WNetAddConnection2(&nr,NULL,szUser,0);
548 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
554 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
555 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
556 FILE_FLAG_WRITE_THROUGH, NULL);
558 if (fh == INVALID_HANDLE_VALUE) {
559 gle = GetLastError();
560 if (gle && ioctlDebug ) {
563 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
566 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
572 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
579 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
584 /* return fh and success code */
590 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
596 rcount = reqp->mp - reqp->data;
599 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
600 return EINVAL; /* not supposed to happen */
603 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
604 /* failed to write */
605 gle = GetLastError();
608 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
612 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
614 gle = GetLastError();
617 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
621 reqp->nbytes = ioCount; /* set # of bytes available */
622 reqp->mp = reqp->data; /* restart marshalling */
629 MarshallLong(fs_ioctlRequest_t * reqp, long val)
631 memcpy(reqp->mp, &val, 4);
637 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
639 /* not enough data left */
640 if (reqp->nbytes < 4) {
642 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
647 memcpy(valp, reqp->mp, 4);
653 /* includes marshalling NULL pointer as a null (0 length) string */
655 MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
660 count = strlen(stringp) + 1; /* space required including null */
664 /* watch for buffer overflow */
665 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
667 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
672 memcpy(reqp->mp, stringp, count);
679 /* take a path with a drive letter, possibly relative, and return a full path
680 * without the drive letter. This is the full path relative to the working
681 * dir for that drive letter. The input and output paths can be the same.
684 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
694 if (pathp[0] != 0 && pathp[1] == ':') {
695 /* there's a drive letter there */
703 if ( firstp[0] == '\\' && firstp[1] == '\\') {
704 /* UNC path - strip off the server and sharename */
706 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
707 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
711 if ( firstp[i] == 0 ) {
712 strcpy(outPathp,"\\");
714 strcpy(outPathp,&firstp[--i]);
717 } else if (firstp[0] == '\\' || firstp[0] == '/') {
718 /* already an absolute pathname, just copy it back */
719 strcpy(outPathp, firstp);
723 GetCurrentDirectory(sizeof(origPath), origPath);
726 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
727 /* a drive has been specified and it isn't our current drive.
728 * to get path, switch to it first. Must case-fold drive letters
729 * for user convenience.
735 if (!SetCurrentDirectory(newPath)) {
736 code = GetLastError();
739 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
745 /* now get the absolute path to the current wdir in this drive */
746 GetCurrentDirectory(sizeof(tpath), tpath);
748 strcpy(outPathp, tpath + 2); /* skip drive letter */
749 else if ( tpath[0] == '\\' && tpath[1] == '\\') {
750 /* UNC path - strip off the server and sharename */
752 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
753 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
757 if ( tpath[i] == 0 ) {
758 strcpy(outPathp,"\\");
760 strcpy(outPathp,&tpath[--i]);
763 /* this should never happen */
764 strcpy(outPathp, tpath);
767 /* if there is a non-null name after the drive, append it */
769 int len = strlen(outPathp);
770 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
771 strcat(outPathp, "\\");
772 strcat(outPathp, firstp);
775 /* finally, if necessary, switch back to our home drive letter */
777 SetCurrentDirectory(origPath);
784 pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
786 fs_ioctlRequest_t preq;
792 code = GetIoctlHandle(pathp, &reqHandle);
801 /* init the request structure */
802 InitFSRequest(&preq);
804 /* marshall the opcode, the path name and the input parameters */
805 MarshallLong(&preq, opcode);
806 /* when marshalling the path, remove the drive letter, since we already
807 * used the drive letter to find the AFS daemon; we don't need it any more.
808 * Eventually we'll expand relative path names here, too, since again, only
809 * we understand those.
812 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
814 CloseHandle(reqHandle);
819 strcpy(fullPath, "");
822 MarshallString(&preq, fullPath);
823 if (blobp->in_size) {
824 memcpy(preq.mp, blobp->in, blobp->in_size);
825 preq.mp += blobp->in_size;
828 /* now make the call */
829 code = Transceive(reqHandle, &preq);
831 CloseHandle(reqHandle);
835 /* now unmarshall the return value */
836 if (UnmarshallLong(&preq, &temp) != 0) {
837 CloseHandle(reqHandle);
842 CloseHandle(reqHandle);
843 errno = CMtoUNIXerror(temp);
845 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
849 /* otherwise, unmarshall the output parameters */
850 if (blobp->out_size) {
851 temp = blobp->out_size;
852 if (preq.nbytes < temp)
854 memcpy(blobp->out, preq.mp, temp);
855 blobp->out_size = temp;
858 /* and return success */
859 CloseHandle(reqHandle);