1 /* 2 * Copyright 2008, François Revol, <revol@free.fr>. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <Alert.h> 8 #include <Catalog.h> 9 #include <Screen.h> 10 #include <String.h> 11 #include <View.h> 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <unistd.h> 17 #include <pwd.h> 18 19 #include "LoginApp.h" 20 #include "LoginWindow.h" 21 #include "DesktopWindow.h" 22 23 #ifdef __HAIKU__ 24 #include <RosterPrivate.h> 25 #include <shadow.h> 26 #include "multiuser_utils.h" 27 #endif 28 29 #undef B_TRANSLATION_CONTEXT 30 #define B_TRANSLATION_CONTEXT "Login App" 31 32 const char *kLoginAppSig = "application/x-vnd.Haiku-Login"; 33 34 35 LoginApp::LoginApp() 36 : BApplication(kLoginAppSig), 37 fEditShelfMode(false), 38 fModalMode(true) 39 { 40 } 41 42 43 LoginApp::~LoginApp() 44 { 45 } 46 47 48 void 49 LoginApp::ReadyToRun() 50 { 51 BScreen screen; 52 53 if (fEditShelfMode) { 54 BAlert* alert = new BAlert(B_TRANSLATE("Info"), B_TRANSLATE("You can customize the " 55 "desktop shown behind the Login application by dropping replicants" 56 " onto it.\n" 57 "\n" 58 "When you are finished just quit the application (Alt-Q)."), 59 B_TRANSLATE("OK")); 60 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 61 alert->Go(NULL); 62 } else { 63 BRect frame(0, 0, 450, 150); 64 frame.OffsetBySelf(screen.Frame().Width()/2 - frame.Width()/2, 65 screen.Frame().Height()/2 - frame.Height()/2); 66 fLoginWindow = new LoginWindow(frame); 67 fLoginWindow->Show(); 68 } 69 70 fDesktopWindow = new DesktopWindow(screen.Frame(), fEditShelfMode); 71 fDesktopWindow->Show(); 72 // TODO: add a shelf with Activity Monitor replicant :) 73 } 74 75 76 void 77 LoginApp::MessageReceived(BMessage *message) 78 { 79 bool reboot = false; 80 81 switch (message->what) { 82 case kAttemptLogin: 83 message->PrintToStream(); 84 TryLogin(message); 85 // TODO 86 break; 87 #ifdef __HAIKU__ 88 case kHaltAction: 89 reboot = false; 90 // FALLTHROUGH 91 case kRebootAction: 92 { 93 BRoster roster; 94 BRoster::Private rosterPrivate(roster); 95 status_t error = rosterPrivate.ShutDown(reboot, false, false); 96 if (error < B_OK) { 97 BString msg(B_TRANSLATE("Error: %1")); 98 msg.ReplaceFirst("%1", strerror(error)); 99 BAlert* alert = new BAlert(("Error"), msg.String(), 100 B_TRANSLATE("OK")); 101 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 102 alert->Go(); 103 } 104 break; 105 } 106 case kSuspendAction: 107 { 108 BAlert* alert = new BAlert(B_TRANSLATE("Error"), 109 B_TRANSLATE("Unimplemented"), B_TRANSLATE("OK")); 110 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 111 alert->Go(); 112 break; 113 } 114 #endif 115 default: 116 BApplication::MessageReceived(message); 117 } 118 } 119 120 121 void 122 LoginApp::ArgvReceived(int32 argc, char **argv) 123 { 124 for (int i = 1; i < argc; i++) { 125 BString arg(argv[i]); 126 //printf("[%d]: %s\n", i, argv[i]); 127 if (arg == "--edit") 128 fEditShelfMode = true; 129 else if (arg == "--nonmodal") 130 fModalMode = false; 131 else /*if (arg == "--help")*/ { 132 printf(B_TRANSLATE("Login application for Haiku\nUsage:\n")); 133 printf("%s [--nonmodal] [--edit]\n", argv[0]); 134 printf(B_TRANSLATE("--nonmodal Do not make the window modal\n")); 135 printf(B_TRANSLATE("--edit Launch in shelf editting mode to " 136 "allow customizing the desktop.\n")); 137 // just return to the shell 138 exit((arg == "--help") ? 0 : 1); 139 return; 140 } 141 } 142 } 143 144 145 void 146 LoginApp::TryLogin(BMessage *message) 147 { 148 status_t err; 149 const char *login; 150 const char *password; 151 BMessage reply(kLoginBad); 152 if (message->FindString("login", &login) == B_OK) { 153 if (message->FindString("password", &password) < B_OK) 154 password = NULL; 155 err = ValidateLogin(login, password); 156 printf(B_TRANSLATE_COMMENT("ValidateLogin: %s\n", 157 "A message returned from the ValidateLogin function. " 158 "It can be \"B_OK\"."), strerror(err)); 159 if (err == B_OK) { 160 reply.what = kLoginOk; 161 message->SendReply(&reply); 162 163 if (password == NULL) 164 return; 165 166 // start a session 167 //kSetProgress 168 StartUserSession(login); 169 } else { 170 reply.AddInt32("error", err); 171 message->SendReply(&reply); 172 return; 173 } 174 175 } else { 176 reply.AddInt32("error", EINVAL); 177 message->SendReply(&reply); 178 return; 179 } 180 } 181 182 183 status_t 184 LoginApp::ValidateLogin(const char *login, const char *password) 185 { 186 struct passwd *pwd; 187 188 pwd = getpwnam(login); 189 if (!pwd) 190 return ENOENT; 191 if (strcmp(pwd->pw_name, login)) 192 return ENOENT; 193 194 if (password == NULL) { 195 // we only want to check is login exists. 196 return B_OK; 197 } 198 199 #ifdef __HAIKU__ 200 if (verify_password(pwd, getspnam(login), password)) 201 return B_OK; 202 #else 203 // for testing 204 if (strcmp(crypt(password, pwd->pw_passwd), pwd->pw_passwd) == 0) 205 return B_OK; 206 #endif 207 208 return B_PERMISSION_DENIED; 209 } 210 211 212 status_t 213 LoginApp::StartUserSession(const char *login) 214 { 215 return B_ERROR; 216 } 217 218 219 int 220 LoginApp::getpty(char *pty, char *tty) 221 { 222 static const char major[] = "pqrs"; 223 static const char minor[] = "0123456789abcdef"; 224 uint32 i, j; 225 int32 fd = -1; 226 227 for (i = 0; i < sizeof(major); i++) 228 { 229 for (j = 0; j < sizeof(minor); j++) 230 { 231 sprintf(pty, "/dev/pt/%c%c", major[i], minor[j]); 232 sprintf(tty, "/dev/tt/%c%c", major[i], minor[j]); 233 fd = open(pty, O_RDWR|O_NOCTTY); 234 if (fd >= 0) 235 { 236 return fd; 237 } 238 } 239 } 240 241 return fd; 242 } 243