<++> qtip/qtip.h /* * qtip.h * 12/04/1997 * twitch * twitch@aye.net * * a quick nt investigative probe. (mis)uses null sessions to collect * sundry information about a WindowsNT server. distribute as you * please. be alert, look alive, and act like you kow. * * '...i should dismiss him, in order to teach him that pleasure consists * not in what i enjoy, but in having my own way.' * -sk, either/or */ #include #include #include #include "lm.h" #define k16 16384 #define TARG_LEN 255 #define USER_LEN 22 void handle_error(DWORD); void prepend_str(char *, char*); int open_session(); int procure_userlist(); int procure_sharelist(); void parse_cl(int, char **); void usage(char *); int powerup(int, char **); void bail(const char *); int close_session(); void get_usr_info(wchar_t *); /* couple o globals to make my life easier */ u_int OPT_SHARES, OPT_USERS, OPT_GETUI; u_int OPT_NODEL, VERB; char target[TARG_LEN]; WCHAR utarg[TARG_LEN]; WCHAR user[USER_LEN]; NETRESOURCE nr; <--> <++> qtip/qtip.c /* * qtip.c * 10/04/1997 * twitch * twitch@aye.net * * a quick nt investigative probe * link against kernel32.lib, libc.lib and wsock32.lib. * qtip -h for usage. distribute as you please. * */ #include "qtip.h" int main(int argc, char *argv[]) { if( (powerup(argc, argv)) ) return(1); if( (open_session()) != 0) return(1); if(OPT_SHARES) procure_sharelist(); if(OPT_USERS) procure_userlist(); if(OPT_GETUI) get_usr_info(utarg); close_session(); return(0); } int open_session() { DWORD r; nr.dwType = RESOURCETYPE_ANY; nr.lpLocalName = NULL; nr.lpProvider = NULL; nr.lpRemoteName = target; if(VERB) printf("establishing null session with %s...\n", target); r = WNetAddConnection2(&nr, "", "", 0); if(r != NO_ERROR){ handle_error(r); return -1; } if(VERB) printf("connection established\n"); return 0; } /* * procure_userlist() * just use the old lm NetUserEnum() because there isnt comparable * functionality in the WNet sect. i just wish the win32 api was * more bloated and obtuse. */ int procure_userlist() { NET_API_STATUS nas; LPBYTE *buf = NULL; DWORD entread, totent, rhand; DWORD maxlen = 0xffffffff; USER_INFO_0 *usrs; unsigned int i; int cc = 0; entread = totent = rhand = nas = 0; if( (buf = (LPBYTE*)malloc(k16)) == NULL) bail("malloc probs\n"); if(VERB) wprintf(L"\ngetting userlist from %s...\n", utarg); nas = NetUserEnum(utarg, 0, 0, buf, maxlen, &entread, &totent, &rhand); if(nas != NERR_Success){ fprintf(stderr, "couldnt enum users, "); handle_error(nas); goto cleanup; } cc = sizeof(USER_INFO_0) * entread; if( (usrs = (USER_INFO_0 *)malloc(cc)) == NULL){ fprintf(stderr, "malloc probs\n"); goto cleanup; } memcpy(usrs, *buf, cc); for(i = 0; i < entread; i++){ wcscpy(user, usrs[i].usri0_name); wprintf(L"%s\n", user); if(VERB) get_usr_info(utarg); } cleanup: if(buf) free(buf); return 0; } /* * get_user_info() * attempt to gather some interesting facts about * a user */ void get_usr_info(LPWSTR utarg) { NET_API_STATUS nas; USER_INFO_1 usrinfos; LPBYTE *buf = NULL; if( !(buf = (LPBYTE *)malloc(sizeof(USER_INFO_1))) ) bail("malloc probs\n"); nas = NetUserGetInfo(utarg, user, 1, buf); if(nas){ fwprintf(stderr, L"couldnt get user info for for %s, ", user); handle_error(nas); } else{ memcpy(&usrinfos, *buf, sizeof(USER_INFO_1)); /* most of these will never happen, but nothings lost trying */ if( (UF_PASSWD_NOTREQD & usrinfos.usri1_flags) ) printf("\t-password not required, how about that.\n"); if( (UF_ACCOUNTDISABLE & usrinfos.usri1_flags) ) printf("\t-account disabled\n"); if( (UF_LOCKOUT & usrinfos.usri1_flags) ) printf("\t-account locked out\n"); if( (UF_DONT_EXPIRE_PASSWD & usrinfos.usri1_flags) ) printf("\t-password doesnt expire\n"); if( (UF_PASSWD_CANT_CHANGE & usrinfos.usri1_flags) ) printf("\t-user cant change password\n"); if( (UF_WORKSTATION_TRUST_ACCOUNT & usrinfos.usri1_flags) ) printf("\t-account for some other box in this domain\n"); if( (UF_SERVER_TRUST_ACCOUNT & usrinfos.usri1_flags) ) printf("\t-account for what is prolly the BDC\n"); if( (UF_INTERDOMAIN_TRUST_ACCOUNT & usrinfos.usri1_flags) ) printf("\t-interdomain permit to trust account\n"); } free(buf); } /* * procure_sharelist() * strangely enough, this retrieves a sharelist from target */ int procure_sharelist() { DWORD r; DWORD bufsize = 16384, cnt = 0xFFFFFFFF; HANDLE enhan; void *buf; NETRESOURCE *res; u_int i; if( (buf = malloc(bufsize)) == NULL){ fprintf(stderr, "malloc probs, bailing\n"); return -1; } nr.dwScope = RESOURCE_CONNECTED; nr.dwType = RESOURCETYPE_ANY; nr.dwDisplayType = 0; nr.dwUsage = RESOURCEUSAGE_CONTAINER; nr.lpLocalName = NULL; nr.lpRemoteName = (LPTSTR)target; nr.lpComment = NULL; nr.lpProvider = NULL; r = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, RESOURCEUSAGE_CONNECTABLE, &nr , &enhan); if(r != 0){ free(buf); printf("open_enum failed, sorry- "); handle_error(r); return -1; } r = WNetEnumResource(enhan, &cnt, buf, &bufsize); if(r != 0){ free(buf); printf("enum_res failed- "); handle_error(r); return -1; } res = (NETRESOURCE*)malloc(cnt * sizeof(NETRESOURCE)); if(res == NULL){ free(buf); printf("malloc probs, i wont be listing shares.\n"); return -1; } memcpy(res, buf, (cnt * sizeof(NETRESOURCE)) ); for(i = 0; i < cnt; i++){ if(VERB) printf("\nshare name:\t"); printf("%s\n", res[i].lpRemoteName); if(VERB){ printf("share type:\t"); if(res[i].dwType = RESOURCETYPE_DISK) printf("disk"); else printf("printer"); printf("\ncomment:\t%s\n", res[i].lpComment); } } free(buf); free(res); return 0; } /* * close_session() * clean up our mess */ int close_session() { DWORD r; WSACleanup(); if(!OPT_NODEL) r = WNetCancelConnection2(target, 0, TRUE); if(r != 0){ fprintf(stderr, "couldnt delete %s, returned %d\n", target, r); return -1; } else{ if(VERB) printf("connection to %s deleted\n", target); } return 0; } /* * handle_error() * util function to deal with some errors. */ void handle_error(DWORD err) { switch(err){ case ERROR_ACCESS_DENIED: fprintf(stderr, "access is denied.\n"); break; case ERROR_BAD_NET_NAME: fprintf(stderr, "bad net name.\n"); break; case ERROR_EXTENDED_ERROR: fprintf(stderr, "an extended error occurred.\n"); break; case ERROR_INVALID_PASSWORD: fprintf(stderr, "invalid password.\n"); break; case ERROR_LOGON_FAILURE: fprintf(stderr, "bad username or password.\n"); break; case NO_ERROR: fprintf(stderr, "it worked\n"); break; case ERROR_BAD_NETPATH: fprintf(stderr, "network path not found.\n"); break; default: fprintf(stderr, "a random error occurred (%d).\n", err); } } /* * prepend_str() * util funk to prepend chars to a string */ void prepend_str(char *orgstr, char *addthis) { orgstr = _strrev(orgstr); addthis = _strrev(addthis); strcat(orgstr, addthis); orgstr = _strrev(orgstr); } /* * parse_cl() * try and make sense of the command line. no, i dont have a win32 getopt. * yes, i know i should */ void parse_cl(int argc, char **argv) { int i, cc; char opt; DWORD r; OPT_SHARES = OPT_USERS = VERB = 0; for(i = 1; i < (argc); i++){ if( (*argv[i]) == '-'){ opt = *(argv[i]+1); switch(opt){ case 'a': OPT_SHARES = 1; OPT_USERS = 1; break; case 's': OPT_SHARES = 1; break; case 'u': OPT_USERS = 1; break; case 'g': OPT_GETUI = 1; if( (strlen(argv[i+1])) > USER_LEN) bail("username too long (must be < 21)"); ZeroMemory(user, USER_LEN); cc = strlen(argv[++i]); r = MultiByteToWideChar(CP_ACP, 0, argv[i], cc, user, (cc + 2)); break; case 'd': OPT_NODEL = 1; break; case 'v': VERB++; break; default: if( (opt != 'h') && (opt != '?') ) fprintf(stderr, "unknown option '%c'\n", opt); usage(argv[0]); break; } } } if( (OPT_SHARES) && (VERB) ) printf("listing shares\n"); if( (OPT_USERS) && (VERB) ) printf("listing users\n"); if( (OPT_GETUI) && (VERB) ) wprintf(L"getting infos about user %s\n", user); if(VERB) printf("verbosity = %d\n", VERB); } /* * powerup() * just init stuff and parse the command line */ int powerup(int argc, char **argv) { struct hostent *hent; u_long addie; WORD werd; WSADATA data; char buf[256]; int cc = 0, ucc = 0; if(argc < 3) usage(argv[0]); parse_cl(argc, argv); ZeroMemory(buf, 256); strcpy(buf, argv[argc - 1]); /* if not unc format get the ip */ if(buf[0] != '\\'){ if(VERB > 1) printf("target not in unc\n"); werd = MAKEWORD(1, 1); if( (WSAStartup(werd, &data)) !=0 ) bail("couldnt init winsock\n"); hent = (struct hostent *)malloc(sizeof(struct hostent)); if(hent == NULL) bail("malloc probs\n"); if( (addie = inet_addr(buf)) == INADDR_NONE){ hent = gethostbyname(buf); if(hent == NULL){ fprintf(stderr, "fatal: couldnt resolve %s.\n", buf); return -1; } ZeroMemory(buf, 256); strcpy(buf, inet_ntoa(*(struct in_addr *)*hent->h_addr_list)); } prepend_str(buf, "\\\\"); } else fprintf(stderr, "target already in unc\n"); if( (strlen(buf) > (TARG_LEN - 1)) ){ free(buf); bail("hostname too long (must be < 255 chars.)"); return -1; } ZeroMemory(target, TARG_LEN); strcpy(target, buf); ZeroMemory(utarg, TARG_LEN); cc = strlen(target); ucc = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, target, cc, utarg, cc); if(ucc < 1){ bail("unicode conversion probs, sorry"); return -1; } return 0; } void usage(char *prog) { fprintf(stderr, "usage: %s [asughv] \n", prog); fprintf(stderr, "\t-s:\t\tget share list\n"); fprintf(stderr, "\t-u:\t\tget user list\n"); fprintf(stderr, "\t-g: \tget infos about just \n"); fprintf(stderr, "\t-d:\t\tleave connection established on exit\n"); fprintf(stderr, "\t-a:\t\t-s + -u\n"); fprintf(stderr, "\t-h, -?:\t\tdisplay this help\n"); fprintf(stderr, "\t-v:\t\tbe verbose (use twice to be garrolous)\n"); exit(0); } /* * bail() * just whine and die */ void bail(const char *msg) { fprintf(stderr, "fatal: %s\n", msg); close_session(); exit(1); }