diff --git a/login.c b/login.c index e11269b..f3e6380 100644 --- a/login.c +++ b/login.c @@ -7,6 +7,461 @@ #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 */ + + /* + * NetWare-like header, but blue for Mars NWE: + * blue separator + * blue title line + * blue separator + * then normal black prompt area. + */ + login_fill_line(1, 0x1f); /* white on blue */ + login_fill_line(2, 0x1f); /* white on blue */ + login_write_attr(36, 2, "Mars NWE", 0x1f); + 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 try_login_script_file(char *name) +{ + return(read_command_file(name)); +} + +static int run_login_script(void) +{ + char profile[200]; + char drive; + + /* + * Novell LOGIN looks for the system login script using server based paths, + * for example \\SERVER\SYS\PUBLIC\NET$LOG.DAT. Try that first. + */ + if (*script_file_server) { + sprintf(profile, "\\\\%s\\SYS\\PUBLIC\\NET$LOG.DAT", script_file_server); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "\\\\%s\\SYS\\PUBLIC\\net$log.dat", script_file_server); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "\\\\%s\\SYS\\LOGIN\\LOGIN", script_file_server); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "\\\\%s\\SYS\\LOGIN\\NET$LOG.DAT", script_file_server); + if (try_login_script_file(profile) != -2) return(0); + } + + /* + * Then try current directory and the executable path. LOGIN.EXE is often + * executed from PUBLIC, so this covers SYS:PUBLIC\NET$LOG.DAT without + * relying on an absolute drive path. + */ + if (try_login_script_file("NET$LOG.DAT") != -2) return(0); + if (try_login_script_file("net$log.dat") != -2) return(0); + if (try_login_script_file("LOGIN") != -2) return(0); + if (try_login_script_file("login") != -2) return(0); + + if (*prgpath) { + sprintf(profile, "%sNET$LOG.DAT", prgpath); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "%snet$log.dat", prgpath); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "%sLOGIN", prgpath); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "%slogin", prgpath); + if (try_login_script_file(profile) != -2) return(0); + } + + /* + * Fallbacks for requesters/runtimes that cannot open UNC from C fopen(). + */ + if (try_login_script_file("\\PUBLIC\\NET$LOG.DAT") != -2) return(0); + if (try_login_script_file("\\public\\net$log.dat") != -2) return(0); + if (try_login_script_file("\\PUBLIC\\LOGIN") != -2) return(0); + if (try_login_script_file("\\public\\login") != -2) return(0); + + if (try_login_script_file("\\LOGIN\\LOGIN") != -2) return(0); + if (try_login_script_file("\\login\\login") != -2) return(0); + if (try_login_script_file("\\LOGIN\\NET$LOG.DAT") != -2) return(0); + if (try_login_script_file("\\login\\net$log.dat") != -2) return(0); + + for (drive = 'C'; drive <= 'Z'; drive++) { + sprintf(profile, "%c:\\PUBLIC\\NET$LOG.DAT", drive); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "%c:\\public\\net$log.dat", drive); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "%c:\\PUBLIC\\LOGIN", drive); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "%c:\\LOGIN\\LOGIN", drive); + if (try_login_script_file(profile) != -2) return(0); + + sprintf(profile, "%c:\\LOGIN\\NET$LOG.DAT", drive); + if (try_login_script_file(profile) != -2) return(0); + } + + return(-2); +} + + static int do_change_object_passwd(char *name, uint16 objtyp, char *oldpassword, @@ -140,9 +595,7 @@ static void getstr(char *what, char *str, int rsize, int doecho) static int login_usage(void) { - fprintf(stderr, "usage:\t%s [-u] [user | user password]\n", funcname); - fprintf(stderr, "\t-u : use unecrypted password\n" ); - return(-1); + return(login_help()); } int func_login(int argc, char *argv[], int mode) @@ -152,10 +605,23 @@ int func_login(int argc, char *argv[], int mode) uint8 uname[200]; uint8 upasswd[200]; SEARCH_VECTOR save_drives; + int interactive_login = 0; + int no_script = 0; if (argc > 1) { - if (argv[1][0] == '-') { - if (argv[1][1] == 'u') option |= 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++; @@ -168,13 +634,18 @@ int func_login(int argc, char *argv[], int mode) 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("Login", uname, sizeof(uname)-1, 1); + 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("Password", upasswd, sizeof(upasswd)-1, 0); + getstr("Enter your password", upasswd, sizeof(upasswd)-1, 0); upstr(upasswd); result = do_object_login(uname, 0x1, upasswd, option); } @@ -186,10 +657,18 @@ int func_login(int argc, char *argv[], int mode) } else break; } if (result > -1) { - char profile[200]; + 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(); - sprintf(profile, "%slogin", prgpath); - read_command_file(profile); + + if (!no_script) + run_login_script(); } else { (void)set_search_drive_vektor(save_drives); } @@ -324,36 +803,53 @@ 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); + 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 **argv=build_argv(buf, 512, linebuf); - if (argv != NULL) { - int argc=0; - char **pp=argv; - while (*pp) { - argc++; - pp++; + 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); } - upstr(argv[0]); - if (argc > 2 && !strcmp(argv[0], "ECHO")) { - char *p=argv[argc-1]; - while (p-- > argv[1]) { - if (*p=='\0') *p=32; - } - argc=2; - } - call_func_entry(argc, argv); 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); }