1/*
2 * Copyright 2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel Dörfler, <axeld@pinc-software.de>
7 *		Ingo Weinhold <ingo_weinhold@gmx.de>
8 */
9
10
11#include <pwd.h>
12
13#include <Button.h>
14#include <Catalog.h>
15#include <LayoutBuilder.h>
16#include <NetworkSettings.h>
17#include <NetworkSettingsAddOn.h>
18#include <StringView.h>
19#include <TextView.h>
20
21#include <NetServer.h>
22#include <RegistrarDefs.h>
23#include <user_group.h>
24#include <util/KMessage.h>
25
26#include "ServiceListItem.h"
27#include "ServiceView.h"
28
29
30using namespace BNetworkKit;
31
32
33#undef B_TRANSLATION_CONTEXT
34#define B_TRANSLATION_CONTEXT "SSHServiceAddOn"
35
36
37static const uint32 kMsgToggleService = 'tgls';
38
39
40class SSHServiceAddOn : public BNetworkSettingsAddOn {
41public:
42								SSHServiceAddOn(image_id image,
43									BNetworkSettings& settings);
44	virtual						~SSHServiceAddOn();
45
46	virtual	BNetworkSettingsItem*
47								CreateNextItem(uint32& cookie);
48};
49
50
51class SSHServiceView : public ServiceView {
52public:
53								SSHServiceView(BNetworkSettings& settings);
54	virtual						~SSHServiceView();
55
56protected:
57	virtual	void				Enable();
58};
59
60
61class SSHServiceItem : public BNetworkSettingsItem {
62public:
63								SSHServiceItem(BNetworkSettings& settings);
64	virtual						~SSHServiceItem();
65
66	virtual	BNetworkSettingsType
67								Type() const;
68
69	virtual BListItem*			ListItem();
70	virtual BView*				View();
71
72	virtual	status_t			Revert();
73	virtual bool				IsRevertable();
74
75	virtual void				SettingsUpdated(uint32 which);
76
77private:
78			BNetworkSettings&	fSettings;
79			BListItem*			fItem;
80			ServiceView*		fView;
81};
82
83
84// #pragma mark -
85
86
87SSHServiceView::SSHServiceView(BNetworkSettings& settings)
88	:
89	ServiceView("ssh", NULL, B_TRANSLATE("SSH server"), B_TRANSLATE(
90		"The SSH server allows you to "
91		"remotely access your machine with a terminal session, as well as "
92		"file access using the SCP and SFTP protocols."), settings)
93{
94}
95
96
97SSHServiceView::~SSHServiceView()
98{
99}
100
101
102void
103SSHServiceView::Enable()
104{
105	if (getpwnam("sshd") == NULL) {
106		// We need to create a dedicated user for the service
107		// The following code is copied from useradd, and should be moved
108		// to a public class.
109		gid_t groupID = 100;
110
111		// Find an unused user ID
112		uid_t userID = 1000;
113		while (getpwuid(userID) != NULL)
114			userID++;
115
116		const char* home = "/boot/home";
117		int expiration = 99999;
118		int inactive = -1;
119		const char* shell = "/bin/sh";
120		const char* realName = "";
121
122		int min = -1;
123		int max = -1;
124		int warn = 7;
125
126		// prepare request for the registrar
127		KMessage message(BPrivate::B_REG_UPDATE_USER);
128		if (message.AddInt32("uid", userID) == B_OK
129			&& message.AddInt32("gid", groupID) == B_OK
130			&& message.AddString("name", "sshd") == B_OK
131			&& message.AddString("password", "x") == B_OK
132			&& message.AddString("home", home) == B_OK
133			&& message.AddString("shell", shell) == B_OK
134			&& message.AddString("real name", realName) == B_OK
135			&& message.AddString("shadow password", "!") == B_OK
136			&& message.AddInt32("last changed", time(NULL)) == B_OK
137			&& message.AddInt32("min", min) == B_OK
138			&& message.AddInt32("max", max) == B_OK
139			&& message.AddInt32("warn", warn) == B_OK
140			&& message.AddInt32("inactive", inactive) == B_OK
141			&& message.AddInt32("expiration", expiration) == B_OK
142			&& message.AddInt32("flags", 0) == B_OK
143			&& message.AddBool("add user", true) == B_OK) {
144			// send the request
145			KMessage reply;
146			status_t error = send_authentication_request_to_registrar(message,
147				reply);
148			if (error != B_OK) {
149				fprintf(stderr, "Error: Failed to create user: %s\n",
150					strerror(error));
151			}
152		}
153	}
154
155	BNetworkServiceSettings settings;
156	settings.SetName("ssh");
157	settings.SetStandAlone(true);
158
159	settings.AddArgument("/bin/sshd");
160	settings.AddArgument("-D");
161
162	BMessage service;
163	if (settings.GetMessage(service) == B_OK)
164		fSettings.AddService(service);
165}
166
167
168// #pragma mark -
169
170
171SSHServiceItem::SSHServiceItem(BNetworkSettings& settings)
172	:
173	fSettings(settings),
174	fItem(new ServiceListItem("ssh", B_TRANSLATE("SSH server"), settings)),
175	fView(NULL)
176{
177}
178
179
180SSHServiceItem::~SSHServiceItem()
181{
182	if (fView->Parent() == NULL)
183		delete fView;
184
185	delete fItem;
186}
187
188
189BNetworkSettingsType
190SSHServiceItem::Type() const
191{
192	return B_NETWORK_SETTINGS_TYPE_SERVICE;
193}
194
195
196BListItem*
197SSHServiceItem::ListItem()
198{
199	return fItem;
200}
201
202
203BView*
204SSHServiceItem::View()
205{
206	if (fView == NULL)
207		fView = new SSHServiceView(fSettings);
208
209	return fView;
210}
211
212
213status_t
214SSHServiceItem::Revert()
215{
216	return fView != NULL ? fView->Revert() : B_OK;
217}
218
219
220bool
221SSHServiceItem::IsRevertable()
222{
223	return fView != NULL ? fView->IsRevertable() : false;
224}
225
226
227void
228SSHServiceItem::SettingsUpdated(uint32 which)
229{
230	if (fView != NULL)
231		fView->SettingsUpdated(which);
232}
233
234
235// #pragma mark -
236
237
238SSHServiceAddOn::SSHServiceAddOn(image_id image,
239	BNetworkSettings& settings)
240	:
241	BNetworkSettingsAddOn(image, settings)
242{
243}
244
245
246SSHServiceAddOn::~SSHServiceAddOn()
247{
248}
249
250
251BNetworkSettingsItem*
252SSHServiceAddOn::CreateNextItem(uint32& cookie)
253{
254	if (cookie++ == 0)
255		return new SSHServiceItem(Settings());
256
257	return NULL;
258}
259
260
261// #pragma mark -
262
263
264extern "C"
265BNetworkSettingsAddOn*
266instantiate_network_settings_add_on(image_id image, BNetworkSettings& settings)
267{
268	return new SSHServiceAddOn(image, settings);
269}
270