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 32const char *kLoginAppSig = "application/x-vnd.Haiku-Login"; 33 34 35LoginApp::LoginApp() 36 : BApplication(kLoginAppSig), 37 fEditShelfMode(false), 38 fModalMode(true) 39{ 40} 41 42 43LoginApp::~LoginApp() 44{ 45} 46 47 48void 49LoginApp::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 76void 77LoginApp::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 121void 122LoginApp::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 145void 146LoginApp::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 183status_t 184LoginApp::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 212status_t 213LoginApp::StartUserSession(const char *login) 214{ 215 return B_ERROR; 216} 217 218 219int 220LoginApp::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