/* login.c 21-May-96 */ /**************************************************************** * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * ****************************************************************/ #include "net.h" #include "nwcrypt.h" #ifndef BLACK #define BLACK 0 #endif #ifndef BLUE #define BLUE 1 #endif #ifndef LIGHTGRAY #define LIGHTGRAY 7 #endif #ifndef WHITE #define WHITE 15 #endif static uint8 script_login_name[64]; static uint8 script_file_server[52]; static char **build_argv(char *buf, int bufsize, char *str); extern int read_command_file(char *fstr); extern int get_fs_name(int connid, char *name); static uint8 login_video_attr = 0x07; static void login_gotoxy(int x, int y) { REGS regs; regs.h.ah = 0x02; regs.h.bh = 0x00; regs.h.dh = (uint8)(y - 1); regs.h.dl = (uint8)(x - 1); int86(0x10, ®s, ®s); } static void login_cls_attr(uint8 attr) { REGS regs; regs.h.ah = 0x06; regs.h.al = 0x00; regs.h.bh = attr; regs.h.ch = 0; regs.h.cl = 0; regs.h.dh = 24; regs.h.dl = 79; int86(0x10, ®s, ®s); login_gotoxy(1, 1); } static void login_write_attr(int x, int y, const char *s, uint8 attr) { REGS regs; int col = x; while (*s) { login_gotoxy(col++, y); regs.h.ah = 0x09; regs.h.al = (uint8)*s++; regs.h.bh = 0; regs.h.bl = attr; regs.x.cx = 1; int86(0x10, ®s, ®s); } login_gotoxy(col, y); } static void login_fill_line(int y, uint8 attr) { REGS regs; login_gotoxy(1, y); regs.h.ah = 0x09; regs.h.al = ' '; regs.h.bh = 0; regs.h.bl = attr; regs.x.cx = 80; int86(0x10, ®s, ®s); } static void login_screen_normal(void) { login_video_attr = 0x07; } static int login_help(void) { fprintf(stdout, "\n"); fprintf(stdout, " LOGIN General Help Mars NWE\n"); fprintf(stdout, " ------------------------------------------------------------------------\n"); fprintf(stdout, " Purpose: To gain access to the network.\n"); fprintf(stdout, " Syntax: LOGIN [/VER] [[Server | Tree/][Username] [/options]\n"); fprintf(stdout, "\n"); fprintf(stdout, " To: Use:\n"); fprintf(stdout, " Login without running login scripts /NS\n"); fprintf(stdout, " Clear the screen before executing /CLS\n"); fprintf(stdout, " Specify a script file /S filename\n"); fprintf(stdout, " Display version information /VER\n"); fprintf(stdout, "\n"); fprintf(stdout, " Examples:\n"); fprintf(stdout, " LOGIN SUPERVISOR\n"); fprintf(stdout, " LOGIN MARS/SUPERVISOR\n"); fprintf(stdout, "\n"); return(0); } static void login_banner(void) { login_cls_attr(0x07); /* normal black background */ /* * Official LOGIN shows a colored separator, title line, colored separator, * then returns to the normal black screen for the prompt. Use blue instead * of Novell red and show "Mars NWE". */ login_fill_line(1, 0x1f); /* white on blue */ login_write_attr(36, 2, "Mars NWE", 0x0f); /* white on black */ login_fill_line(3, 0x1f); /* white on blue */ login_screen_normal(); login_gotoxy(1, 4); } static char *skip_spaces(char *p) { while (*p == 32 || *p == '\t') p++; return(p); } static void strip_quotes(char *s) { char *d = s; char quote = 0; while (*s) { if (!quote && (*s == '"' || *s == '\'')) { quote = *s++; continue; } if (quote && *s == quote) { quote = 0; s++; continue; } *d++ = *s++; } *d = '\0'; } static void script_put_expanded(char *s) { while (s && *s) { if (!strncmp(s, "%LOGIN_NAME", 11) || !strncmp(s, "%login_name", 11)) { fprintf(stdout, "%s", script_login_name); s += 11; } else if (!strncmp(s, "%FILE_SERVER", 12) || !strncmp(s, "%file_server", 12)) { fprintf(stdout, "%s", script_file_server); s += 12; } else if (!strncmp(s, "%P_STATION", 10) || !strncmp(s, "%p_station", 10)) { fprintf(stdout, "000000000000"); s += 10; } else { fputc(*s++, stdout); } } } static void script_write(char *p) { p = skip_spaces(p); strip_quotes(p); script_put_expanded(p); fputc('\n', stdout); } static void script_join_args(char **argv, int argc) { if (argc > 2) { char *p = argv[argc-1]; while (p-- > argv[1]) { if (*p == '\0') *p = 32; } } } static void script_call_line(char *line) { char *buf; char **argv; int argc = 0; char **pp; buf = xmalloc(512); argv = build_argv(buf, 512, line); if (argv != NULL) { pp = argv; while (*pp) { argc++; pp++; } if (argc > 0) { upstr(argv[0]); call_func_entry(argc, argv); } } xfree(buf); } static int script_eval_if(char *line) { char tmp[512]; char *p; char *q; int neg = 0; strmaxcpy(tmp, line, sizeof(tmp) - 1); upstr(tmp); if (strstr(tmp, "MEMBER OF") != NULL) { if (strstr(tmp, "EVERYONE") != NULL) return(1); return(0); } p = strstr(tmp, "LOGIN_NAME"); if (p != NULL) { q = strstr(p, "<>"); if (q != NULL) neg = 1; else q = strchr(p, '='); if (q != NULL) { char want[64]; char *v; int i = 0; q += neg ? 2 : 1; q = skip_spaces(q); if (*q == '"' || *q == '\'') q++; while (*q && *q != '"' && *q != '\'' && *q != 32 && *q != '\t' && i < 63) { want[i++] = *q++; } want[i] = '\0'; strmaxcpy(tmp, script_login_name, sizeof(tmp) - 1); upstr(tmp); if (neg) return(strcmp(tmp, want) != 0); else return(strcmp(tmp, want) == 0); } } return(0); } static int login_strnicmp(char *a, char *b, int n) { while (n-- > 0) { int ca = *a++; int cb = *b++; if (ca >= 'a' && ca <= 'z') ca -= 32; if (cb >= 'a' && cb <= 'z') cb -= 32; if (ca != cb) return(ca - cb); if (!ca) return(0); } return(0); } static int script_execute_line(char *line) { char work[512]; char cmd[32]; char *p; char *arg; int i; strmaxcpy(work, line, sizeof(work) - 1); p = skip_spaces(work); if (!*p) return(0); i = 0; while (p[i] && p[i] != 32 && p[i] != '\t' && i < 31) { cmd[i] = p[i]; i++; } cmd[i] = '\0'; upstr(cmd); arg = skip_spaces(p + i); if (!strcmp(cmd, "WRITE") || !strcmp(cmd, "ECHO")) { script_write(arg); return(0); } if (!strcmp(cmd, "PAUSE")) { fprintf(stdout, "Strike any key when ready . . ."); fflush(stdout); getch(); fprintf(stdout, "\n"); return(0); } if (!strcmp(cmd, "CLS")) { login_cls_attr(0x07); return(0); } if (!strcmp(cmd, "BREAK")) { return(0); } if (!strcmp(cmd, "SET")) { if (*arg) putglobenv(arg); return(0); } if (!strcmp(cmd, "DRIVE")) { arg = skip_spaces(arg); if ((*arg >= 'A' && *arg <= 'Z') || (*arg >= 'a' && *arg <= 'z')) { if (*arg >= 'a') setdisk(*arg - 'a'); else setdisk(*arg - 'A'); } return(0); } if (!strcmp(cmd, "MAP")) { char up[512]; strmaxcpy(up, arg, sizeof(up) - 1); upstr(up); if (!strncmp(up, "DISPLAY", 7)) { return(0); } if (!strncmp(up, "INS ", 4) || !strncmp(up, "INSERT ", 7)) { char callbuf[512]; char *a = arg; if (!login_strnicmp(up, "INS ", 4)) a += 4; else a += 7; sprintf(callbuf, "PATHINS %s", skip_spaces(a)); script_call_line(callbuf); return(0); } if (!strncmp(up, "DEL ", 4) || !strncmp(up, "DELETE ", 7)) { char callbuf[512]; char *a = arg; if (!login_strnicmp(up, "DEL ", 4)) a += 4; else a += 7; sprintf(callbuf, "PATHDEL %s", skip_spaces(a)); script_call_line(callbuf); return(0); } } if (!strcmp(cmd, "EXIT")) { return(1); } script_call_line(p); return(0); } static int run_login_script(void) { char profile[200]; /* * NetWare LOGIN normally executes the system login script from SYS:PUBLIC. * Try current directory first because LOGIN.EXE is often run from PUBLIC, * then the program path, then common SYS:PUBLIC and SYS:LOGIN paths. */ if (read_command_file("net$log.dat") != -2) return(0); if (read_command_file("NET$LOG.DAT") != -2) return(0); if (read_command_file("login") != -2) return(0); if (read_command_file("LOGIN") != -2) return(0); if (*prgpath) { sprintf(profile, "%snet$log.dat", prgpath); if (read_command_file(profile) != -2) return(0); sprintf(profile, "%sNET$LOG.DAT", prgpath); if (read_command_file(profile) != -2) return(0); sprintf(profile, "%slogin", prgpath); if (read_command_file(profile) != -2) return(0); sprintf(profile, "%sLOGIN", prgpath); if (read_command_file(profile) != -2) return(0); } if (read_command_file("\\net$log.dat") != -2) return(0); if (read_command_file("\\NET$LOG.DAT") != -2) return(0); if (read_command_file("\\public\\net$log.dat") != -2) return(0); if (read_command_file("\\PUBLIC\\NET$LOG.DAT") != -2) return(0); if (read_command_file("\\public\\login") != -2) return(0); if (read_command_file("\\PUBLIC\\LOGIN") != -2) return(0); if (read_command_file("f:\\public\\net$log.dat") != -2) return(0); if (read_command_file("f:\\PUBLIC\\NET$LOG.DAT") != -2) return(0); if (read_command_file("f:\\public\\login") != -2) return(0); if (read_command_file("f:\\PUBLIC\\LOGIN") != -2) return(0); if (read_command_file("\\login\\login") != -2) return(0); if (read_command_file("\\LOGIN\\LOGIN") != -2) return(0); if (read_command_file("\\login\\net$log.dat") != -2) return(0); if (read_command_file("\\LOGIN\\NET$LOG.DAT") != -2) return(0); return(-2); } static int do_change_object_passwd(char *name, uint16 objtyp, char *oldpassword, char *newpassword) { uint8 key[8]; if (!ncp_17_17(key)) { uint32 objid = ncp_17_35(name, objtyp); if (objid) { uint8 oldpwd[16]; /* old passwd as stored by server */ uint8 newpwd[16]; /* new passwd as stored by server */ uint8 cryptkey[8]; uint8 tmpid[4]; uint8 passwdx; int newlen; memcpy(cryptkey, key, 8); U32_TO_BE32(objid, tmpid); shuffle(tmpid, oldpassword, strlen(oldpassword), oldpwd); shuffle(tmpid, newpassword, strlen(newpassword), newpwd); nw_encrypt(cryptkey, oldpwd, cryptkey); /* * Same keyed change password transformation as ncpfs * ncp_change_login_passwd(): encrypt both 8-byte halves of the * stored new password using the stored old password as key material. * newpassencrypt() intentionally mutates oldpwd; the passwd length * byte must be calculated afterwards, just like ncpfs does it. */ newpassencrypt(oldpwd, newpwd); newpassencrypt(oldpwd + 8, newpwd + 8); newlen = strlen(newpassword); if (newlen > 63) newlen = 63; passwdx = (uint8)(((newlen ^ oldpwd[0] ^ oldpwd[1]) & 0x7f) | 0x40); if (!ncp_17_4b(cryptkey, name, objtyp, passwdx, newpwd)) { ;; return(0); } } } /* * Fallback for old servers/requesters where Get Encryption Key is not * available. Keep the original unencrypted behavior as fallback only. */ if (!ncp_17_40(name, objtyp, oldpassword, newpassword)) { ;; return(0); } return(-1); } static int do_object_login(char *name, uint16 objtyp, char *password, int option) { uint8 key[8]; if (!(option & 1) && !ncp_17_17(key)) { uint32 objid = ncp_17_35(name, objtyp); if (objid) { uint8 buff[128]; uint8 encrypted[8]; uint8 tmpid[4]; U32_TO_BE32(objid, tmpid); shuffle(tmpid, password, strlen(password), buff); nw_encrypt(key, buff, encrypted); if (!ncp_17_18(encrypted, name, objtyp)) { ;; return(0); } } } else { /* now we use old unencrypted algorithmus */ if (!ncp_17_14(name, objtyp, password)) { return(0); } } return(-1); } static void beep(void) { fprintf(stdout, "\007"); } static int get_raw_str(uint8 *s, int maxlen, int doecho) /* returns len of readed str */ { int len = 0; while (len < maxlen){ int key = getch(); if (key == '\r' || key == '\n') break; switch (key) { case 8 : if (len) { --len; --s; if (doecho) { fprintf(stdout, "\010 \010"); fflush(stdout); } } else beep(); continue; case '\t': beep(); continue; default : *s++=(uint8)key; len++; break; } /* switch */ if (doecho) { fprintf(stdout, "%c", (uint8)key); fflush(stdout); } } *s='\0'; return(len); } static void getstr(char *what, char *str, int rsize, int doecho) { fprintf(stdout, "%s: ", what); fflush(stdout); get_raw_str(str, rsize, doecho); fprintf(stdout, "\n"); } static int login_usage(void) { return(login_help()); } int func_login(int argc, char *argv[], int mode) { int result=-1; int option=0; uint8 uname[200]; uint8 upasswd[200]; SEARCH_VECTOR save_drives; int interactive_login = 0; int no_script = 0; if (argc > 1) { if (!strcmp(argv[1], "/?") || !strcmp(argv[1], "-?") || !strcmp(argv[1], "?")) return(login_help()); if (!strcmp(argv[1], "/VER") || !strcmp(argv[1], "-VER")) { fprintf(stdout, "Mars NWE LOGIN 0.99\n"); return(0); } } if (argc > 1) { if (argv[1][0] == '-' || argv[1][0] == '/') { if (argv[1][1] == 'u' || argv[1][1] == 'U') option |= 1; else if (!strcmp(argv[1], "/NS") || !strcmp(argv[1], "-NS")) no_script = 1; else if (!strcmp(argv[1], "/CLS") || !strcmp(argv[1], "-CLS")) login_cls_attr(0x07); else return(login_usage()); argc--; argv++; } } get_search_drive_vektor(save_drives); remove_nwpathes(); if (argc > 1) strmaxcpy(uname, argv[1], sizeof(uname) -1); else uname[0]='\0'; if (argc > 2) strmaxcpy(upasswd, argv[2], sizeof(upasswd) -1); else upasswd[0]='\0'; if (!uname[0]) { interactive_login = 1; login_banner(); } while (result) { if (!uname[0]) getstr("Enter your login name", uname, sizeof(uname)-1, 1); if (uname[0]) { upstr(uname); upstr(upasswd); if ((result = do_object_login(uname, 0x1, upasswd, option)) < 0 && !*upasswd) { getstr("Enter your password", upasswd, sizeof(upasswd)-1, 0); upstr(upasswd); result = do_object_login(uname, 0x1, upasswd, option); } if (result < 0) { fprintf(stdout, "Login incorrect\n\n"); uname[0] = '\0'; upasswd[0] = '\0'; } } else break; } if (result > -1) { strmaxcpy(script_login_name, uname, sizeof(script_login_name) - 1); if (get_fs_name(1, script_file_server)) strcpy(script_file_server, "MARS"); if (interactive_login) fprintf(stdout, "You are attached to server %s.\n", script_file_server); remove_nwpathes(); if (!no_script) run_login_script(); } else { (void)set_search_drive_vektor(save_drives); } return(result); } int func_logout(int argc, char *argv[], int mode) { remove_nwpathes(); if (logout()) { fprintf(stderr, "logout=%d\n", neterrno); return(1); } return(0); } int func_passwd(int argc, char *argv[], int mode) { int result=0; uint8 uname[100]; uint8 upasswd[130]; uint32 my_obj_id; if (ncp_14_46(&my_obj_id) < 0 || my_obj_id == MAX_U32 || !my_obj_id) { fprintf(stderr, "Cannot get actual user id\n"); result = -1; } if (!result && argc > 1) { uint32 obj_id; strmaxcpy(uname, argv[1], sizeof(uname) -1); upstr(uname); obj_id = ncp_17_35(uname, 1); if (!obj_id) { fprintf(stderr, "Unkwown user: %s\n", uname); return(-1); } } else if (!result) { uint16 obj_typ; if (ncp_17_36(my_obj_id, uname, &obj_typ) || obj_typ != 1) { fprintf(stderr, "Cannot get actual username\n"); result=-1; } } if (!result && *uname) { uint8 newpasswd[130]; uint8 newpasswd2[130]; if (my_obj_id == 1L) *upasswd='\0'; else { getstr("Old password", upasswd, sizeof(upasswd)-1, 0); upstr(upasswd); } getstr("New password", newpasswd, sizeof(newpasswd)-1, 0); getstr("New password again", newpasswd2, sizeof(newpasswd2)-1, 0); if (!strcmp(newpasswd, newpasswd2)) { upstr(uname); upstr(newpasswd); if (do_change_object_passwd(uname, 1, upasswd, newpasswd) < 0) result = -1; } else { result = -1; fprintf(stderr, "Password misspelled\n"); } } if (result < 0) fprintf(stderr, "Password not changed"); return(result); } static int get_line(FILE *f, char *buff, int bufsize, uint8 *str, int strsize) /* returns command line or -1 if ends */ { if ((FILE*) NULL != f) { while (fgets(buff, bufsize, f) != NULL){ char *p = buff; char *beg = NULL; char c; int len=0; while (0 != (c = *p++) && c != '\n' && c != '\r' && c != '#') { if (!beg){ if (c != '\t' && c != 32) { beg = p - 1; len = 1; } } else ++len; } if (len) { strmaxcpy((uint8*)str, (uint8*)beg, min(len, strsize-1)); return(0); } } } return(-1); } static char **build_argv(char *buf, int bufsize, char *command) /* routine returns **argv for use with execv routines */ /* buf will contain the path component */ { int len = strlen(command); int offset = ((len+4) / 4) * 4; /* aligned offset for **argv */ int components = (bufsize - offset) / 4; if (components > 1) { /* minimal argv[0] + NULL */ char **argv = (char **)(buf+offset); char **pp = argv; char *p = buf; char c; int i=0; --components; memcpy(buf, command, len); memset(buf+len, 0, bufsize - len); *pp = p; while ((0 != (c = *p++)) && i < components) { if (c == 32 || c == '\t') { *(p-1) = '\0'; if (*p != 32 && *p != '\t') { *(++pp)=p; i++; } } else if (!i && c == '/') { /* here i must get argv[0] */ *pp=p; } } return(argv); } return(NULL); } int read_command_file(char *fstr) { FILE *f=fopen(fstr, "r"); int result=-1; if (f != NULL) { char *linebuf = xmalloc(512); char *buf = xmalloc(512); int stack[16]; int level = 0; int active = 1; while (get_line(f, buf, 512, linebuf, 512) > -1) { char tmp[512]; char *p; strmaxcpy(tmp, linebuf, sizeof(tmp) - 1); p = skip_spaces(tmp); upstr(p); if (!strncmp(p, "IF ", 3)) { if (level < 16) { stack[level++] = active; active = active && script_eval_if(linebuf); } result = 0; continue; } if (!strcmp(p, "END") || !strncmp(p, "END ", 4)) { if (level > 0) active = stack[--level]; result = 0; continue; } if (!active) { result = 0; continue; } if (script_execute_line(linebuf)) break; result = 0; } fclose(f); xfree(linebuf); xfree(buf); } else result=-2; return(result); } int func_profile(int argc, char *argv[], int mode) { if (argc < 2) { fprintf(stderr, "usage:\t%s fn\n", funcname); return(-1); } if (read_command_file(argv[1]) == -2) { fprintf(stderr, "command file %s not found\n", argv[1]); } return(0); } int func_cwd(int argc, char *argv[], int mode) { char pathname[65]; int len; if (argc < 2) { fprintf(stderr, "usage:\t%s path\n", funcname); return(-1); } strmaxcpy(pathname, argv[1], sizeof(pathname) -1); korrpath(pathname); if (0 != (len = strlen(pathname))) { char *p=pathname+len-1; if (*p == '/' || *p == ':') { *(++p) = '.'; *(++p) = '\0'; len++; } if (!chdir(pathname)) { if (len > 2 && *(pathname+1) == ':') /* device changed */ setdisk(*pathname - 'a' ); } else { fprintf(stderr, "cannot chdir to %s\n", pathname); return(1); } return(0); } else return(-1); } int func_echo(int argc, char *argv[], int mode) { if (argc > 1) fprintf(stdout, "%s\n", argv[1]); return(0); } int func_exec(int argc, char *argv[], int mode) { if (argc > 1) { char *buf = xmalloc(512); char *buff = xmalloc(512); char *p = buff; int k = 0; char **nargv; while (++k < argc) { strcpy(p, argv[k]); p += strlen(argv[k]); *p++ = 32; *p = '\0'; } nargv=build_argv(buf, 512, buff); xfree(buff); if (nargv != NULL) { if (!mode) spawnvp(P_WAIT, buf, (const char *const *)nargv); else execvp(buf, (const char *const *)nargv); } xfree(buf); } return(0); }