yannstatic/static/2019/10/17/Linux-gestion-des-utilisateurs-et-permissions-serveur-web.html

2577 lines
231 KiB
HTML
Raw Permalink Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>Linux, gestion des utilisateurs ,permissions des fichiers et répertoires dun serveur web - YannStatic</title>
<meta name="description" content="gestion des utilisateurs et des permissions dun serveur web">
<link rel="canonical" href="https://static.rnmkcy.eu/2019/10/17/Linux-gestion-des-utilisateurs-et-permissions-serveur-web.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
<!-- - include head/favicon.html - -->
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
<!-- end custom head snippets --><script>(function() {
window.isArray = function(val) {
return Object.prototype.toString.call(val) === '[object Array]';
};
window.isString = function(val) {
return typeof val === 'string';
};
window.hasEvent = function(event) {
return 'on'.concat(event) in window.document;
};
window.isOverallScroller = function(node) {
return node === document.documentElement || node === document.body || node === window;
};
window.isFormElement = function(node) {
var tagName = node.tagName;
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
};
window.pageLoad = (function () {
var loaded = false, cbs = [];
window.addEventListener('load', function () {
var i;
loaded = true;
if (cbs.length > 0) {
for (i = 0; i < cbs.length; i++) {
cbs[i]();
}
}
});
return {
then: function(cb) {
cb && (loaded ? cb() : (cbs.push(cb)));
}
};
})();
})();
(function() {
window.throttle = function(func, wait) {
var args, result, thisArg, timeoutId, lastCalled = 0;
function trailingCall() {
lastCalled = new Date;
timeoutId = null;
result = func.apply(thisArg, args);
}
return function() {
var now = new Date,
remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
if (remaining <= 0) {
clearTimeout(timeoutId);
timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
} else if (!timeoutId) {
timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
};
})();
(function() {
var Set = (function() {
var add = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (data[i] === item) {
return;
}
}
this.size ++;
data.push(item);
return data;
};
var Set = function(data) {
this.size = 0;
this._data = [];
var i;
if (data.length > 0) {
for (i = 0; i < data.length; i++) {
add.call(this, data[i]);
}
}
};
Set.prototype.add = add;
Set.prototype.get = function(index) { return this._data[index]; };
Set.prototype.has = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (this.get(i) === item) {
return true;
}
}
return false;
};
Set.prototype.is = function(map) {
if (map._data.length !== this._data.length) { return false; }
var i, j, flag, tData = this._data, mData = map._data;
for (i = 0; i < tData.length; i++) {
for (flag = false, j = 0; j < mData.length; j++) {
if (tData[i] === mData[j]) {
flag = true;
break;
}
}
if (!flag) { return false; }
}
return true;
};
Set.prototype.values = function() {
return this._data;
};
return Set;
})();
window.Lazyload = (function(doc) {
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
var createNode = function(name, attrs) {
var node = doc.createElement(name), attr;
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
node.setAttribute(attr, attrs[attr]);
}
}
return node;
};
var end = function(type, url) {
var s, q, qi, cbs, i, j, cur, val, flag;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
s[url] = true;
for (i = 0; i < q.length; i++) {
cur = q[i];
if (cur.urls.has(url)) {
qi = cur, val = qi.urls.values();
qi && (cbs = qi.callbacks);
for (flag = true, j = 0; j < val.length; j++) {
cur = val[j];
if (!s[cur]) {
flag = false;
}
}
if (flag && cbs && cbs.length > 0) {
for (j = 0; j < cbs.length; j++) {
cbs[j].call(context);
}
qi.load = true;
}
}
}
}
};
var load = function(type, urls, callback) {
var s, q, qi, node, i, cur,
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
for (i = 0; i < q.length; i++) {
cur = q[i];
if (_urls.is(cur.urls)) {
qi = cur;
break;
}
}
val = _urls.values();
if (qi) {
callback && (qi.load || qi.callbacks.push(callback));
callback && (qi.load && callback());
} else {
q.push({
urls: _urls,
callbacks: callback ? [callback] : [],
load: false
});
for (i = 0; i < val.length; i++) {
node = null, url = val[i];
if (s[url] === undefined) {
(type === 'js' ) && (node = createNode('script', { src: url }));
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
if (node) {
node.onload = (function(type, url) {
return function() {
end(type, url);
};
})(type, url);
(doc.head || doc.body).appendChild(node);
s[url] = false;
}
}
}
}
}
};
return {
js: function(url, callback) {
load('js', url, callback);
},
css: function(url, callback) {
load('css', url, callback);
}
};
})(this.document);
})();
</script><script>
(function() {
var TEXT_VARIABLES = {
version: '2.2.6',
sources: {
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
jquery: '/assets/js/jquery.min.js',
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
gitalk: {
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
},
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
},
site: {
toc: {
selectors: 'h1,h2,h3'
}
},
paths: {
search_js: '/assets/search.js'
}
};
window.TEXT_VARIABLES = TEXT_VARIABLES;
})();
</script>
</head>
<body>
<div class="root" data-is-touch="false">
<div class="layout--page js-page-root">
<!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
<div class="page__main-inner">
<div class="page__header d-print-none">
<header class="header"><div class="main">
<div class="header__title">
<div class="header__brand">
<svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewbox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.516 C 137.230 220.679,138.000 221.92
" href="/">YannStatic</a>
</div>
<!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
<!-- Champ de recherche -->
<div id="searchbox" class="search search--dark" style="visibility: visible">
<div class="main">
<div class="search__header"></div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text">
<!-- <div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div> -->
</div>
</div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json: '/search.json',
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a></li>'
})
</script>
<!-- Fin déclaration champ de recherche -->
</div>
<nav class="navigation">
<ul>
<li class="navigation__item"><a href="/archive.html">Etiquettes</a></li>
<li class="navigation__item"><a href="/htmldoc.html">Documents</a></li>
<li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li>
<li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li>
</ul>
</nav>
</div>
</header>
</div>
<div class="page__content"><div class="main"><div class="grid grid--reverse">
<div class="col-main cell cell--auto">
<!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div>
<!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">Linux, gestion des utilisateurs ,permissions des fichiers et répertoires dun serveur web</h1></header></div>
<meta itemprop="headline" content="Linux, gestion des utilisateurs ,permissions des fichiers et répertoires dun serveur web">
<div class="article__info clearfix">
<ul class="left-col menu">
<li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=archlinux">archlinux</a>
2024-10-31 20:18:37 +01:00
</li>
<li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=cli">cli</a>
2024-10-31 20:18:37 +01:00
</li>
</ul>
<ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF">17 oct.  2019</span>
<span title="Modification" style="color:#00FF7F">20 févr. 2024</span>
</li></ul>
</div>
<meta itemprop="datePublished" content="2024-02-20T00:00:00+01:00">
<meta itemprop="keywords" content="archlinux,cli">
<div class="js-article-content">
<div class="layout--article">
<!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page"></button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody">
<details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><p><em>gestion des utilisateurs et des permissions dun serveur web</em></p>
<h1 id="gérer-les-utilisateurs-à-partir-de-la-ligne-de-commande-sous-linux">Gérer les utilisateurs à partir de la ligne de commande sous Linux</h1>
<p>Lune des responsabilités principales de ladministration Linux est la gestion des utilisateurs. Grâce à lutilisation de la ligne de commande, la création dutilisateur peut être complétée à distance ou par programme. Une fois que vous avez créé un utilisateur, vous pouvez ensuite lajouter à des groupes ou leur attribuer des privilèges plus élevés. De plus, vous pouvez garder une trace daudit sur ce qui a été fait sur votre serveur et sur tout problème potentiel.</p>
<p>Si vous avez développé un logiciel ou programmé pour le Web, vous connaissez peut-être la politique de ne jamais faire confiance aux utilisateurs. Le même principe sapplique dans dautres domaines de lutilisation des ordinateurs en ce qui concerne la participation des utilisateurs. Ne donnez accès quà ceux qui en ont besoin et quand ils en ont besoin. Une délégation généreuse de privilèges pourrait permettre un accès non spécifié et non autorisé aux informations et aux données de base de tiers.
Voir les utilisateurs existants</p>
<p>Lun des moyens les plus rapides de visualiser les utilisateurs consiste à utiliser les commandes cat (concaténer) ou more (pager) pour afficher la liste des utilisateurs du système. Le fichier que vous devez afficher est le fichier «/ etc / passwd». Ce fichier stocke tous les comptes dutilisateur et les informations de connexion de lutilisateur.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo cat /etc/passwd
</code></pre></div></div>
<h3 id="utilisation-de-la-commande-useradd">Utilisation de la commande useradd</h3>
<p><code class="language-plaintext highlighter-rouge">useradd</code> est un binaire de bas niveau disponible sur la plupart des distributions. Cette commande est généralement moins utilisée en raison de son caractère moins convivial et intuitif par rapport à la commande <code class="language-plaintext highlighter-rouge">adduser</code> . Cependant, il y a très peu de différences et lune ou lautre peut être utilisée.</p>
<p>Pour en savoir plus sur useradd, exécutez la commande man ou ajoutez help pour obtenir un aperçu rapide.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>man useradd
useradd --help
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Usage: useradd <span class="o">[</span>options] LOGIN
useradd <span class="nt">-D</span>
useradd <span class="nt">-D</span> <span class="o">[</span>options]
Options:
<span class="nt">-b</span>, <span class="nt">--base-dir</span> BASE_DIR base directory <span class="k">for </span>the home directory of the
new account
<span class="nt">--btrfs-subvolume-home</span> use BTRFS subvolume <span class="k">for </span>home directory
<span class="nt">-c</span>, <span class="nt">--comment</span> COMMENT GECOS field of the new account
<span class="nt">-d</span>, <span class="nt">--home-dir</span> HOME_DIR home directory of the new account
<span class="nt">-D</span>, <span class="nt">--defaults</span> print or change default useradd configuration
<span class="nt">-e</span>, <span class="nt">--expiredate</span> EXPIRE_DATE expiration <span class="nb">date </span>of the new account
<span class="nt">-f</span>, <span class="nt">--inactive</span> INACTIVE password inactivity period of the new account
<span class="nt">-g</span>, <span class="nt">--gid</span> GROUP name or ID of the primary group of the new
account
<span class="nt">-G</span>, <span class="nt">--groups</span> GROUPS list of supplementary <span class="nb">groups </span>of the new
account
<span class="nt">-h</span>, <span class="nt">--help</span> display this <span class="nb">help </span>message and <span class="nb">exit</span>
<span class="nt">-k</span>, <span class="nt">--skel</span> SKEL_DIR use this alternative skeleton directory
<span class="nt">-K</span>, <span class="nt">--key</span> <span class="nv">KEY</span><span class="o">=</span>VALUE override /etc/login.defs defaults
<span class="nt">-l</span>, <span class="nt">--no-log-init</span> <span class="k">do </span>not add the user to the lastlog and
faillog databases
<span class="nt">-m</span>, <span class="nt">--create-home</span> create the user<span class="s1">'s home directory
-M, --no-create-home do not create the user'</span>s home directory
<span class="nt">-N</span>, <span class="nt">--no-user-group</span> <span class="k">do </span>not create a group with the same name as
the user
<span class="nt">-o</span>, <span class="nt">--non-unique</span> allow to create <span class="nb">users </span>with duplicate
<span class="o">(</span>non-unique<span class="o">)</span> UID
<span class="nt">-p</span>, <span class="nt">--password</span> PASSWORD encrypted password of the new account
<span class="nt">-r</span>, <span class="nt">--system</span> create a system account
<span class="nt">-R</span>, <span class="nt">--root</span> CHROOT_DIR directory to <span class="nb">chroot </span>into
<span class="nt">-P</span>, <span class="nt">--prefix</span> PREFIX_DIR prefix directory where are located the /etc/<span class="k">*</span> files
<span class="nt">-s</span>, <span class="nt">--shell</span> SHELL login shell of the new account
<span class="nt">-u</span>, <span class="nt">--uid</span> UID user ID of the new account
<span class="nt">-U</span>, <span class="nt">--user-group</span> create a group with the same name as the user
</code></pre></div></div>
<p>Pour ajouter un utilisateur à laide de <code class="language-plaintext highlighter-rouge">useradd</code> , tapez useradd et le nom du login que vous souhaitez créer.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo useradd --create-home testuser
</code></pre></div></div>
<p>Dans le cas ci-dessus, lutilisateur “testuser” sera créé. Par défaut, cette commande ne créera que lutilisateur et rien dautre. Si vous avez besoin dun répertoire de base pour cet utilisateur, ajoutez lindicateur <code class="language-plaintext highlighter-rouge">--create-home</code> pour créer le répertoire de base de lutilisateur.</p>
<h3 id="utilisation-de-la-commande-adduser">Utilisation de la commande adduser</h3>
<p>La commande <code class="language-plaintext highlighter-rouge">adduser</code> est un script Perl qui créera lutilisateur de la même façon que la commande useradd . La différence réside dans le fait quil sagit dune commande interactive qui vous invitera à définir le mot de passe, le chemin du répertoire personnel, etc. Notez que sur certaines distributions, telles que Red Hat et CentOS, adduser est un lien symbolique vers useradd, et Sur dautres distributions comme Arch Linux, adduser est fourni sous forme de paquet qui nest pas installé par défaut.</p>
<p>Lutilisation de cette commande créera un groupe pour lutilisateur en utilisant son identifiant par défaut. Les autres valeurs par défaut se trouvent généralement dans le fichier useradd à ladresse “/etc/default”.</p>
<p>Dans ce fichier, vous pouvez modifier les paramètres par défaut pour les utilisateurs créés avec useradd, tels que le shell et le répertoire de base.</p>
<p><img src="/images/linux-useradd-conf.png" alt="" width="500"></p>
<p>Exécutez la commande <code class="language-plaintext highlighter-rouge">adduser</code> suivante:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo adduser testuser
</code></pre></div></div>
<p><img src="/images/linux-adduser.png" alt="" width="500"></p>
<p>Cela vous indiquera les valeurs par défaut que vous souhaitez définir et vous demandera le mot de passe.</p>
<h3 id="mots-de-passe-et-sécurité">Mots de passe et sécurité</h3>
<p>Lajout dun mot de passe pour un utilisateur nécessitera lexécution de la commande <code class="language-plaintext highlighter-rouge">passwd</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo passwd testuser
</code></pre></div></div>
<p>Sans les privilèges de super-utilisateur, exécuter passwd ne changera que le mot de passe de lutilisateur connecté. Cette commande testera la complexité du mot de passe. Sous Ubuntu, les exigences en matière de mot de passe sont définies dans le fichier de mot de passe commun situé dans «/ec/pam.d». Pour plus dinformations sur la mise à jour de la complexité, reportez-vous à la page de manuel relative à pam-auth-update.</p>
<p><img src="/images/linux-pam-auth-man.png" alt="" width="500"></p>
<h3 id="mise-à-jour-des-informations-utilisateur">Mise à jour des informations utilisateur</h3>
<p>Une fois quun utilisateur est sur le système, vous pouvez consulter le fichier «/etc/passwd» pour afficher les informations de lutilisateur et le mot de passe crypté. Si vous devez apporter des modifications à un utilisateur, vous devrez utiliser la commande <code class="language-plaintext highlighter-rouge">usermod</code> .</p>
<p><img src="/images/linux-usermod-man.png" alt="" width="500"></p>
<p>Par exemple, pour modifier lID utilisateur du compte testuser4 créé ci-dessus, exécutez la commande suivante:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod -u 2022 testuser2
</code></pre></div></div>
<p>Vous pouvez ensuite examiner les modifications dans le fichier «/etc/passwd».</p>
<p><img src="/images/linux-tail-passwd.png" alt=""></p>
<blockquote>
<p>Veillez à ne pas modifier les informations critiques telles que le nom de connexion ou, comme dans ce cas, lID utilisateur. Consultez la page de manuel de usermod pour savoir ce que vous devrez faire si ces éléments sont modifiés.</p>
</blockquote>
<h3 id="ajout-dutilisateurs-au-groupe">Ajout dutilisateurs au groupe</h3>
<p>Il arrive parfois que vous deviez ajouter des utilisateurs à un groupe afin quils disposent des autorisations nécessaires pour exécuter certaines tâches.</p>
<p>Pour ajouter un utilisateur à un groupe:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod -a -G groupname username
</code></pre></div></div>
<blockquote>
<p>Notez que lindicateur -a est nécessaire pour «ajouter» le groupe à lutilisateur. Sinon, vous risquez de retirer lutilisateur du groupe «sudo» sil est supposé avoir lautorisation de superutilisateur.</p>
</blockquote>
<p>Vous pouvez également utiliser la commande <code class="language-plaintext highlighter-rouge">gpasswd</code> pour ajouter/supprimer un utilisateur au/du groupe.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gpasswd -a username groupname
</code></pre></div></div>
<p>Pour supprimer un utilisateur dun groupe:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gpasswd -d username groupname
</code></pre></div></div>
<p>Vérifier les utilisateurs dun groupe , exemple groupe users</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>grep "users" /etc/group
</code></pre></div></div>
<h3 id="suppression-dutilisateurs">Suppression dutilisateurs</h3>
<p>Comme pour les autres commandes utilisateur, la suppression dun utilisateur est précédée de «user» et de laction. Dans ce cas, vous devrez utiliser la commande <code class="language-plaintext highlighter-rouge">userdel</code></p>
<p><img src="/images/linux-userdel-man.png" alt="" width="500"></p>
<p>Prenez note que <code class="language-plaintext highlighter-rouge">userdel</code> ne supprimera pas un utilisateur sil existe des processus utilisant son compte.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo userdel testuser4
</code></pre></div></div>
<h3 id="affichage-des-journaux-utilisateurs">Affichage des journaux utilisateurs</h3>
<p>Selon votre distribution, vous pourrez consulter le journal dauthentification ou le journal sécurisé situé dans «/var/log» pour vérifier les identifiants de connexion des utilisateurs. Ce fichier journal vous donnera les identifiants sur votre système dès quils se produisent. Il sagit dun élément essentiel de la surveillance des événements en cas de violation et du simple fait de sassurer que tout fonctionne comme prévu.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo tail /var/log/auth.log
</code></pre></div></div>
<p>La gestion des utilisateurs est un élément crucial de la gestion des serveurs Linux si plusieurs personnes utilisent votre système. Lutilisation de la ligne de commande vous permettra dadministrer rapidement les utilisateurs et de disposer dun historique de création et de modification de compte. Lune des meilleures utilisations serait peut-être dautomatiser la création à laide dun script shell si plusieurs comptes sont nécessaires à la fois.</p>
<p>Dans les deux cas, veillez à consulter régulièrement vos comptes et à supprimer les comptes devenus inutiles. Assurez-vous que laccès nest accordé quà ceux qui en ont actuellement besoin et surveille fréquemment vos journaux.</p>
<h2 id="permissions-des-fichiers-et-répertoires-dun-serveur-web">Permissions des fichiers et répertoires dun serveur web</h2>
<ul>
<li><a href="https://tech.feub.net/2014/06/permissions-des-fichiers-et-repertoires-dun-serveur-web/">Permissions des fichiers et répertoires dun serveur web (<strong>Article original</strong>)</a></li>
</ul>
<p>Un serveur HTTP peut contenir plusieurs sites, les fichiers de ceux-ci peuvent être gérés par plusieurs utilisateurs, un utilisateur A ayant accès aux fichiers du site A, mais pas à ceux du site B, alors quun utilisateur C, aura accès aux fichiers des site A, B et C par exemple.</p>
<p>Ce qui suit ne sadresse pas à un type de serveur particulier, mais suppose une machine GNU/Linux et un serveur Nginx ou Apache.</p>
<h3 id="les-permissions">Les permissions</h3>
<p>Normalement sous Linux, lorsquun fichier est créé, il hérite du groupe de lutilisateur qui la créé. Dans le cas de fichiers et répertoires relatifs à un serveur web, il est préférable que lorsquun fichier est créé il hérite du groupe du répertoire parent (en général <code class="language-plaintext highlighter-rouge">/var/www</code>), pour faire ceci il faut activer le bit <a href="#droit-sgid">SGID</a> (Set Group ID) du répertoire parent.
Pour se rafraichir un peu les neurones au niveau du concept de permissions sous Linux, voir <a href="http://feub.net/2008/03/setuid-setgid-et-sticky-bit/">ce billet</a>.</p>
<p>Dun autre coté, pour travailler convenablement avec ses collaborateurs, il faut prendre soin de modifier le <a href="https://fr.wikipedia.org/wiki/Umask">umask</a>, le masque de création de fichier par lutilisateur, qui est général placé à <code class="language-plaintext highlighter-rouge">022</code> par défaut, cest-à-dire que lorsquun fichier est créé il aura comme permissions <code class="language-plaintext highlighter-rouge">755</code>, ce fichier nétant pas éditable par le groupe. Changer le umask en <code class="language-plaintext highlighter-rouge">002</code> va placer les permissions dun nouveau fichier en <code class="language-plaintext highlighter-rouge">775</code>.</p>
<h3 id="principes-de-base">Principes de base</h3>
<p>Dans un fonctionnement typique, nous voulons que les utilisateurs aient le droit de lire et écrire sur les fichiers. Ils doivent également avoir le droit dexécution sur les répertoires, ce droit permettant à un utilisateur de traverser un répertoire, donc de lister ce quil contient.
De son coté le serveur web doit pouvoir lire et exécuter les fichiers. A noter quil na pas besoin davoir le droit dexécution x car ceci ne sapplique en général quaux binaires, or un script PHP est un fichier texte interprété. Le serveur HTTP doit également pouvoir lire et « exécuter » les répertoires (entendre: il doit pouvoir les traverser). Enfin certains répertoires peuvent avoir le droit décriture pour donner le droit duploader des fichiers par exemple.</p>
<h3 id="configuration">Configuration</h3>
<p>La configuration sera la suivante : un groupe par site sera créé, les utilisateurs seront ajoutés aux groupes désirés afin dy avoir accès et tous les fichiers et répertoires appartiendront à lutilisateur root. La notion dutilisateur nétant plus importante dans notre cas, on ne fait quaccroitre la sécurité du serveur web en attribuant la propriété des fichiers à lutilisateur root (on est certain quaucun utilisateur du système naura les privilèges de modifier ces fichiers).</p>
<p>Voici un exemple qui peut servir de base :</p>
<ul>
<li>On ajoute un groupe pour le site A :</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd www-site-a
</code></pre></div></div>
<ul>
<li>On fait de même pour le site B :</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd www-site-b
</code></pre></div></div>
<ul>
<li>On ajoute le groupe www-site-a à lutilisateur A :</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usermod -a -G www-site-a usera
</code></pre></div></div>
<ul>
<li>On ajoute le groupe www-site-b à lutilisateur B :</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usermod -a -G www-site-b userb
</code></pre></div></div>
<ul>
<li>Suivant lexemple du début, on ajoute ces deux groupes à lutilisateur C :</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usermod -a -G www-site-a userc
usermod -a -G www-site-b userc
</code></pre></div></div>
<p>A ce stade on peut simplement vérifier les groupes des utilisateurs :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groups userc
userc : userc www-site-a www-site-b
</code></pre></div></div>
<ul>
<li>On change les permissions de tous les fichiers et répertoires recursivement pour chaque site :</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown -R root:www-site-a /var/www/site-a
chown -R root:www-site-b /var/www/site-b
</code></pre></div></div>
<ul>
<li>Tous les répertoires doivent avoir les droits <code class="language-plaintext highlighter-rouge">2775</code> (<a href="#sticky-bit">Sticky Bit</a>) :</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find /var/www -type d -exec chmod 2775 {} +
</code></pre></div></div>
<ul>
<li>Tous les fichiers eux doivent être en 0664 :</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find /var/www -type f -exec chmod 0664 {} +
</code></pre></div></div>
<p>Pour finir, il faut changer le umask en 0002, cela diffère suivant le système. Sous Debian 7.4 ou Fedora 20, il est possible de changer la ligne UMASK du fichier /etc/login.defs.</p>
<h3 id="note-sur-les-dangers-du-chmod-777">Note sur les dangers du chmod 777</h3>
<p>Un fichier ayant les droits 777 est accessible par tous les utilisateurs, nimporte lequel peut modifier et supprimer ce fichier. Ceci reste local aux utilisateurs existants sur la machine, cest une question de confiance aux collègues. Plus important, des fichiers en 777 sont également modifiables par le serveur web lui-même, donc toute faille dans un script peut être catastrophique, une régle de base est de naccorder quune confiance minimum à tout script, car aucun programme nest à labri dune vulnérabilité.</p>
<h2 id="permissions-unix-wikipédia">Permissions UNIX (wikipédia)</h2>
<ul>
<li><a href="https://fr.wikipedia.org/wiki/Permissions_UNIX">Permissions UNIX (wikipédia FR)</a></li>
</ul>
<h3 id="droit-sgid">Droit SGID</h3>
<p><strong>Fichiers</strong><br>
Ce droit fonctionne comme le droit SUID, mais appliqué aux groupes. Il donne à un utilisateur les droits du groupe auquel appartient le propriétaire de lexécutable et non plus les droits du propriétaire.</p>
<p><strong>Répertoires</strong><br>
Ce droit a une tout autre utilisation sil est appliqué à un répertoire. Normalement, lorsquun fichier est créé par un utilisateur, il en est propriétaire, et un groupe par défaut lui est appliqué (généralement users si le fichier a été créé par un utilisateur, et root ou wheel sil a été créé par root). Cependant, lorsquun fichier est créé dans un répertoire portant le droit SGID, alors ce fichier se verra attribuer par défaut le groupe du répertoire. De plus, si cest un autre répertoire qui est créé dans le répertoire portant le droit SGID, ce sous-répertoire portera également ce droit.</p>
<p><strong>Notation</strong><br>
Comme le droit SUID, il vient remplacer le flag x, mais celui des droits du groupe, et la capitale indique le droit dexécution x caché, elle est présente sil nest pas alloué.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ------s--- ou ------S---
</code></pre></div></div>
<p>Un fichier avec les droits</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> -rwxr--r--
</code></pre></div></div>
<p>auquel on ajoute le droit SGID aura donc la notation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> -rwxr-Sr--
</code></pre></div></div>
<p><strong>Valeur</strong><br>
Le droit SGID possède la valeur octale 2000.<br>
Exemple : <code class="language-plaintext highlighter-rouge">- r w x r - S r - -</code> correspond à 2744.</p>
<h3 id="sticky-bit">Sticky Bit</h3>
<p>Ce droit (traduction bit collant) est utilisé pour manier de façon plus subtile les droits décriture dun répertoire. En effet, le droit décriture signifie que lon peut créer et supprimer les fichiers de ce répertoire. Le sticky bit permet de faire la différence entre les deux droits.</p>
<p><strong>Définition</strong><br>
Lorsque ce droit est positionné sur un répertoire, il interdit la suppression dun fichier quil contient à tout utilisateur autre que le propriétaire du fichier. Néanmoins, il est toujours possible pour un utilisateur possédant les droits décriture sur ce fichier de le modifier (par exemple de le transformer en un fichier vide). La création de nouveaux fichiers est toujours possible pour tous les utilisateurs possédant le droit décriture sur ce répertoire. Remarquons que cest le même principe que les pages de Wikipédia, elles sont modifiables mais on ne peut pas les supprimer.</p>
<p>Pour les fichiers, lutilisation est tout autre. Le bit collant (sticky bit) indique alors que ce fichier doit encore rester en mémoire vive après son exécution. Le but était, à lépoque, daméliorer les performances en évitant de charger/décharger un fichier de la mémoire (par exemple, un exécutable ou une bibliothèque logicielle). Le terme sticky (collant) voulait dire que le fichier restait collé en mémoire. Cette fonctionnalité nest toutefois gérée que sur un faible nombre de systèmes Unix comme HP-UX. Aucune version de Linux ne gère cette fonctionnalité du sticky bit.</p>
<p><strong>Notation</strong><br>
Son flag est le t ou T, qui vient remplacer le droit dexécution x des autres utilisateurs que le propriétaire et ceux appartenant au groupe du fichier, de la même façon que les droits SUID et SGID. La capitale fonctionne aussi de la même façon, elle est présente si le droit dexécution x caché nest pas présent.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ---------t ou ---------T
</code></pre></div></div>
<p>Un fichier avec les droits</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> -rwxr-xr-x
</code></pre></div></div>
<p>auquel on ajoute le droit sticky bit aura donc la notation</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> -rwxr-xr-t
</code></pre></div></div>
<p><strong>Valeur</strong><br>
Le droit sticky bit possède la valeur octale 1000.<br>
Exemple : <code class="language-plaintext highlighter-rouge">- r w x r - x r - t</code> correspond à 1755.<br>
Exemple dutilisation</p>
<p>Sur certains systèmes UNIX, le sticky bit est utilisé pour le répertoire /tmp, qui doit être accessible en écriture par tous les utilisateurs, sans que ceux-ci se suppriment leurs fichiers les uns les autres :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> drwxrwxrwt 86 root root 20480 tmp
</code></pre></div></div>
<h2 id="modifier-utilisateur-répertoire-et-groupe">Modifier Utilisateur Répertoire et Groupe</h2>
<p>en mode sudo, modifier le fichier de configuration <code class="language-plaintext highlighter-rouge">sshd_config</code> pour autoriser la connexion en root</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
echo "PermitRootLogin yes" &gt;&gt; /etc/ssh/sshd_config
systemctl restart sshd
ssh root@vps-hostname
</code></pre></div></div>
<h3 id="modifier-utilisateur">Modifier utilisateur</h3>
<p>Linux fournit un outil nommé <code class="language-plaintext highlighter-rouge">usermod</code> spécifiquement pour faire des modifications aux comptes dutilisateurs. Dans ce cas, nous lutilisons pour renommer un compte utilisateur, ce qui est fait en utilisant le drapeau <code class="language-plaintext highlighter-rouge">-l</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/sbin/usermod -l debian ustarter
</code></pre></div></div>
<p class="warning">Lindicateur <code class="language-plaintext highlighter-rouge">-l</code> ne changera que le nom de lutilisateur. Toutes les autres choses attachées à lutilisateur ne seront pas affectées, comme le répertoire personnel et lUID.</p>
<h4 id="changer-répertoire-dorigine">Changer répertoire dorigine</h4>
<p>Pour modifier le répertoire dorigine de lutilisateur, nous utilisons à nouveau la commande <code class="language-plaintext highlighter-rouge">usermod</code>. Cependant, cette fois, nous devons effectuer deux actions : changer le répertoire personnel en un nouveau chemin et déplacer le contenu de lancien chemin vers le nouveau.</p>
<p>Nous définissons le chemin du nouveau répertoire personnel en utilisant loption <code class="language-plaintext highlighter-rouge">-d</code> ou <code class="language-plaintext highlighter-rouge">--home</code> avec le chemin du nouveau répertoire. Nous devons également utiliser loption <code class="language-plaintext highlighter-rouge">-m</code> pour copier le contenu de lancien répertoire personnel dans le nouveau.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/sbin/usermod -d /home/ustarter -m debian
</code></pre></div></div>
<h3 id="renommer-groupe-dun-utilisateur">Renommer groupe dun utilisateur</h3>
<p>Chaque utilisateur sur un système Linux est créé avec un groupe du même nom. Lorsque nous changeons le nom dun utilisateur, le nom de son groupe reste inchangé. Cest une bonne idée de changer également le nom du groupe primaire de lutilisateur.</p>
<p>Pour changer le nom du groupe primaire dun utilisateur, nous utilisons la commande <code class="language-plaintext highlighter-rouge">groupmod</code> avec loption <code class="language-plaintext highlighter-rouge">-n</code>. Nous devons fournir lancien nom et un nouveau nom.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/sbin/groupmod -n debian ustarter
</code></pre></div></div>
<h3 id="en-une-ligne-de-commande">En une ligne de commande</h3>
<p>Pour changer lutilisateur debian en ustarter.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd ustarter; usermod -d /home/ustarter -m -g ustarter -l ustarter debian
</code></pre></div></div>
<p>Cela change le nom, le groupe, le répertoire dorigine et la propriété et le groupe de ce répertoire pour les nouveaux, ainsi que tous les fichiers. Vous vous retrouvez avec un utilisateur quil est impossible de distinguer de celui qui a été créé à lorigine sous le nom de “ustarter”.</p>
<h2 id="renommer-utilisateur-groupe-et-home">Renommer utilisateur, groupe et home</h2>
<h3 id="préambule">Préambule</h3>
<p>Pour pouvoir renommer un utilisateur, il faut que celui-ci ne soit pas connecté. De plus, il faut sassurer quaucun processus ou aucune tache ne sexécute en son nom. Bien entendu, toutes les opérations décrites dans ce tutorial devront être exécutées dans un terminal en mode administrateur (root).</p>
<h3 id="modification-du-groupe">Modification du groupe</h3>
<p>Nous allons tout dabord modifier le nom du groupe correspondant à lutilisateur. Par défaut, un utilisateur a un groupe qui porte son nom, nous souhaitons donc le renommer également. Pour cela, il faut exécuter la commande :
Source code</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupmod -n &lt;nouveau-nom&gt; &lt;ancien-nom&gt;
</code></pre></div></div>
<p>Pour se convaincre que la modification a bien été effectuée, on peut vérifier que le dossier personnel de lutilisateur (/home/&lt;nom-de-lutilisateur&gt;) appartient bien au groupe renommé.</p>
<h3 id="modification-nom-utilisateur">Modification nom utilisateur</h3>
<p>La commande de modification du nom de lutilisateur est plus complexe. En effet, il ne suffit pas de changer le nom, comme pour le groupe, mais dautres opérations sont nécessaires comme :</p>
<ul>
<li>Créer un dossier dutilisateur sous le nouveau nom</li>
<li>Transférer tous les fichiers de lutilisateur dans le nouveau dossier</li>
<li>Modifier le nom complet de lutilisateur (le cas échéant)</li>
</ul>
<p>La commande à exécuter pour effectuer toutes ces opérations est la suivante :
Source code</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usermod -d /home/&lt;nouveau-dossier&gt; -m -l &lt;nouveau-nom&gt; -c &lt;nouveau-nom-complet&gt; &lt;ancien-nom&gt;
</code></pre></div></div>
<p>Lexécution peut prendre un certain temps, en fonction du nombre de fichiers concernés.</p>
<h3 id="recherche-fichier-configuration">Recherche fichier configuration</h3>
<p>Il nest pas rare que les fichiers de configuration de lutilisateur comportent en dur le chemin vers le dossier de lutilisateur ou tout autre paramètre faisant référence au nom de lutilisateur. Il peut donc être intéressant de modifier directement les fichiers pour rétablir les chemins qui auraient été cassés par le changement de nom de dossier. Cependant, jattire votre attention sur le fait quil est absolument nécessaire de faire des sauvegarde, car modifier manuellement les fichiers de configuration peut être hasardeux et peut engendrer des instabilités.</p>
<h1 id="the-complete-guide-to-useradd-command-in-linux">The Complete Guide to “useradd” Command in Linux</h1>
<p>We all are aware about the most popular command called useradd or adduser in Linux. There are times when a Linux System Administrator asked to create user accounts on Linux with some specific properties, limitations or comments.</p>
<p>In Linux, a useradd command is a low-level utility that is used for adding/creating user accounts in Linux and other Unix-like operating systems. The adduser is much similar to useradd command, because it is just a symbolic link to it.
add users in linux</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd command examples
</code></pre></div></div>
<p>In some other Linux distributions, useradd command may comes with lightly difference version. I suggest you to read your documentation, before using our instructions to create new user accounts in Linux.</p>
<p>When we run useradd command in Linux terminal, it performs following major things:</p>
<ul>
<li>It edits /etc/passwd, /etc/shadow, /etc/group and /etc/gshadow files for the newly created User account.</li>
<li>Creates and populate a home directory for the new user.</li>
<li>Sets permissions and ownerships to home directory.</li>
</ul>
<p>Basic syntax of command is:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd [options] username
</code></pre></div></div>
<p>In this article we will show you the most used 15 useradd commands with their practical examples in Linux. We have divided the section into two parts from Basic to Advance usage of command.</p>
<ul>
<li>Part I: Basic usage with 10 examples</li>
<li>Part II: Advance usage with 5 examples</li>
</ul>
<h2 id="part-i--10-basic-usage-of-useradd-commands">Part I 10 Basic Usage of useradd Commands</h2>
<h3 id="1-how-to-add-a-new-user-in-linux">1. How to Add a New User in Linux</h3>
<p>To add/create a new user, all youve to follow the command useradd or adduser with username. The username is a user login name, that is used by user to login into the system.
Only one user can be added and that username must be unique (different from other username already exists on the system).
For example, to add a new user called tecmint, use the following command.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd tecmint
</code></pre></div></div>
<p>When we add a new user in Linux with useradd command it gets created in locked state and to unlock that user account, we need to set a password for that account with passwd command.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd tecmint
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Changing password for user tecmint.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
</code></pre></div></div>
<p>Once a new user created, its entry automatically added to the /etc/passwd file. The file is used to store users information and the entry should be.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tecmint:x:504:504:tecmint:/home/tecmint:/bin/bash
</code></pre></div></div>
<p>The above entry contains a set of seven colon-separated fields, each field has its own meaning. Lets see what are these fields:</p>
<ul>
<li>Username: User login name used to login into system. It should be between 1 to 32 charcters long.</li>
<li>Password: User password (or x character) stored in /etc/shadow file in encrypted format.</li>
<li>User ID (UID): Every user must have a User ID (UID) User Identification Number. By default UID 0 is reserved for root user and UIDs ranging from 1-99 are reserved for other predefined accounts. Further UIDs ranging from 100-999 are reserved for system accounts and groups.</li>
<li>Group ID (GID): The primary Group ID (GID) Group Identification Number stored in /etc/group file.</li>
<li>User Info: This field is optional and allow you to define extra information about the user. For example, user full name. This field is filled by finger command.</li>
<li>Home Directory: The absolute location of users home directory.</li>
<li>Shell: The absolute location of a users shell i.e. /bin/bash.</li>
</ul>
<h3 id="2-create-a-user-with-different-home-directory">2. Create a User with Different Home Directory</h3>
<p>By default useradd command creates a users home directory under /home directory with username. Thus, for example, weve seen above the default home directory for the user tecmint is /home/tecmint.<br>
However, this action can be changed by using -d option along with the location of new home directory (i.e. /data/projects). For example, the following command will create a user anusha with a home directory /data/projects.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -d /data/projects anusha
</code></pre></div></div>
<p>You can see the user home directory and other user related information like user id, group id, shell and comments.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /etc/passwd | grep anusha
anusha:x:505:505::/data/projects:/bin/bash
</code></pre></div></div>
<h3 id="3-create-a-user-with-specific-user-id">3. Create a User with Specific User ID</h3>
<p>In Linux, every user has its own UID (Unique Identification Number). By default, whenever we create a new user accounts in Linux, it assigns userid 500, 501, 502 and so on…<br>
But, we can create users with custom userid with -u option. For example, the following command will create a user navin with custom userid 999.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -u 999 navin
</code></pre></div></div>
<p>Now, lets verify that the user created with a defined userid (999) using following command.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /etc/passwd | grep navin
navin:x:999:999::/home/navin:/bin/bash
</code></pre></div></div>
<blockquote>
<p>NOTE: Make sure the value of a user ID must be unique from any other already created users on the system.</p>
</blockquote>
<h3 id="4-create-a-user-with-specific-group-id">4. Create a User with Specific Group ID</h3>
<p>Similarly, every user has its own GID (Group Identification Number). We can create users with specific group IDs as well with -g option.<br>
Here in this example, we will add a user tarunika with a specific UID and GID simultaneously with the help of -u and -g options.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -u 1000 -g 500 tarunika
</code></pre></div></div>
<p>Now, see the assigned user id and group id in /etc/passwd file.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /etc/passwd | grep tarunika
tarunika:x:1000:500::/home/tarunika:/bin/bash
</code></pre></div></div>
<h3 id="5-add-a-user-to-multiple-groups">5. Add a User to Multiple Groups</h3>
<p>The -G option is used to add a user to additional groups. Each group name is separated by a comma, with no intervening spaces.<br>
Here in this example, we are adding a user tecmint into multiple groups like admins, webadmin and developer.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -G admins,webadmin,developers tecmint
</code></pre></div></div>
<p>Next, verify that the multiple groups assigned to the user with id command.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>id tecmint
uid=1001(tecmint) gid=1001(tecmint)
groups=1001(tecmint),500(admins),501(webadmin),502(developers)
context=root:system_r:unconfined_t:SystemLow-SystemHigh
</code></pre></div></div>
<h3 id="6-add-a-user-without-home-directory">6. Add a User without Home Directory</h3>
<p>In some situations, where we dont want to assign a home directories for a users, due to some security reasons. In such situation, when a user logs into a system that has just restarted, its home directory will be root. When such user uses su command, its login directory will be the previous user home directory.<br>
To create users without their home directories, -M is used. For example, the following command will create a user shilpi without a home directory.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -M shilpi
</code></pre></div></div>
<p>Now, lets verify that the user is created without home directory, using ls command.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls -l /home/shilpi
ls: cannot access /home/shilpi: No such file or directory
</code></pre></div></div>
<h3 id="7-create-a-user-with-account-expiry-date">7. Create a User with Account Expiry Date</h3>
<p>By default, when we add users with useradd command user account never get expires i.e their expiry date is set to 0 (means never expired).<br>
However, we can set the expiry date using -e option, that sets date in YYYY-MM-DD format. This is helpful for creating temporary accounts for a specific period of time.<br>
Here in this example, we create a user aparna with account expiry date i.e. 27th April 2014 in YYYY-MM-DD format.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -e 2014-03-27 aparna
</code></pre></div></div>
<p>Next, verify the age of account and password with chage command for user aparna after setting account expiry date.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chage -l aparna
Last password change : Mar 28, 2014
Password expires : never
Password inactive : never
Account expires : Mar 27, 2014
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
</code></pre></div></div>
<h3 id="8-create-a-user-with-password-expiry-date">8. Create a User with Password Expiry Date</h3>
<p>The -f argument is used to define the number of days after a password expires. A value of 0 inactive the user account as soon as the password has expired. By default, the password expiry value set to -1 means never expire.
Here in this example, we will set a account password expiry date i.e. 45 days on a user tecmint using -e and -f options.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -e 2014-04-27 -f 45 tecmint
</code></pre></div></div>
<h3 id="9-add-a-user-with-custom-comments">9. Add a User with Custom Comments</h3>
<p>The -c option allows you to add custom comments, such as users full name, phone number, etc to /etc/passwd file. The comment can be added as a single line without any spaces.<br>
For example, the following command will add a user mansi and would insert that users full name, Manis Khurana, into the comment field.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -c "Manis Khurana" mansi
</code></pre></div></div>
<p>You can see your comments in /etc/passwd file in comments section.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tail -1 /etc/passwd
mansi:x:1006:1008:Manis Khurana:/home/mansi:/bin/sh
</code></pre></div></div>
<h3 id="10-change-user-login-shell">10. Change User Login Shell</h3>
<p>Sometimes, we add users which has nothing to do with login shell or sometimes we require to assign different shells to our users. We can assign different login shells to a each user with -s option.<br>
Here in this example, will add a user tecmint without login shell i.e. /sbin/nologin shell.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -s /sbin/nologin tecmint
</code></pre></div></div>
<p>You can check assigned shell to the user in /etc/passwd file.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tail -1 /etc/passwd
tecmint:x:1002:1002::/home/tecmint:/sbin/nologin
</code></pre></div></div>
<h2 id="part-ii--5-advance-usage-of-useradd-commands">Part II 5 Advance Usage of useradd Commands</h2>
<h3 id="11-add-a-user-with-specific-home-directory-default-shell-and-custom-comment">11. Add a User with Specific Home Directory, Default Shell and Custom Comment</h3>
<p>The following command will create a user ravi with home directory /var/www/tecmint, default shell /bin/bash and adds extra information about user.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -m -d /var/www/ravi -s /bin/bash -c "TecMint Owner" -U ravi
</code></pre></div></div>
<p>In the above command -m -d option creates a user with specified home directory and the -s option set the users default shell i.e. /bin/bash. The -c option adds the extra information about user and -U argument create/adds a group with the same name as the user.</p>
<h3 id="12-add-a-user-with-home-directory-custom-shell-custom-comment-and-uid-gid">12. Add a User with Home Directory, Custom Shell, Custom Comment and UID GID</h3>
<p>The command is very similar to above, but here we defining shell as /bin/zsh and custom UID and GID to a user tarunika. Where -u defines new users UID (i.e. 1000) and whereas -g defines GID (i.e. 1000).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -m -d /var/www/tarunika -s /bin/zsh -c "TecMint Technical Writer" -u 1000 -g 1000 tarunika
</code></pre></div></div>
<h3 id="13-add-a-user-with-home-directory-no-shell-custom-comment-and-user-id">13. Add a User with Home Directory, No Shell, Custom Comment and User ID</h3>
<p>The following command is very much similar to above two commands, the only difference is here, that we disabling login shell to a user called avishek with custom User ID (i.e. 1019).<br>
Here -s option adds the default shell /bin/bash, but in this case we set login to /usr/sbin/nologin. That means user avishek will not able to login into the system.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -m -d /var/www/avishek -s /usr/sbin/nologin -c "TecMint Sr. Technical Writer" -u 1019 avishek
</code></pre></div></div>
<h3 id="14-add-a-user-with-home-directory-shell-custom-skell-comment-and-user-id">14. Add a User with Home Directory, Shell, Custom Skell Comment and User ID</h3>
<p>The only change in this command is, we used -k option to set custom skeleton directory i.e. /etc/custom.skell, not the default one /etc/skel. We also used -s option to define different shell i.e. /bin/tcsh to user navin.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -m -d /var/www/navin -k /etc/custom.skell -s /bin/tcsh -c "No Active Member of TecMint" -u 1027 navin
</code></pre></div></div>
<h3 id="15-add-a-user-without-home-directory-no-shell-no-group-and-custom-comment">15. Add a User without Home Directory, No Shell, No Group and Custom Comment</h3>
<p>This following command is very different than the other commands explained above. Here we used -M option to create user without users home directory and -N argument is used that tells the system to only create username (without group). The -r arguments is for creating a system user.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -M -N -r -s /bin/false -c "Disabled TecMint Member" clayton
</code></pre></div></div>
<p>For more information and options about useradd, run useradd command on the terminal to see available options.</p>
<h2 id="part-iii-how-to-create-groups-in-linux-groupadd-command">Part III How to Create Groups in Linux (groupadd Command)</h2>
<h3 id="groupadd-command-syntax">groupadd Command Syntax</h3>
<p>The general syntax for the groupadd command is as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd [OPTIONS] GROUPNAME
</code></pre></div></div>
<p>Only the root or a user with sudo privileges can create new groups.</p>
<p>When invoked, groupadd creates a new group using the options specified on the command line plus the default values specified in the /etc/login.defs file.</p>
<h3 id="creating-a-group-in-linux">Creating a Group in Linux</h3>
<p>To create a new group type groupadd followed by the new group name.<br>
For example, to create a new group named mygroup you would run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd mygroup
</code></pre></div></div>
<p>The command adds an entry for the new group to the /etc/group and /etc/gshadow files.<br>
Once the group is created, you can start adding users to the group .<br>
If the group with the same name already exist, the system will print an error message like the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd: group 'mygroup' already exists
</code></pre></div></div>
<p>To suppress the error message if the group exist and to make the command exit successfully, use the <code class="language-plaintext highlighter-rouge">-f (--force)</code> option:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd -f mygroup
</code></pre></div></div>
<h3 id="creating-a-group-with-specific-gid">Creating a Group with Specific GID</h3>
<p>In Linux and Unix-like operating systems, groups are identified by its name and a unique GID (a positive integer).<br>
By default, when a new group is created, the system assigns the next available GID from the range of group IDs specified in the login.defs file.</p>
<p>Use the <code class="language-plaintext highlighter-rouge">-g (--gid)</code> option to create a group with a specific GID.<br>
For example to create a group named mygroup with GID of 1010 you would type:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd -g 1010 mygroup
</code></pre></div></div>
<p>You can verify the groups GID, by listing all groups and filtering the result with grep :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>getent group | grep mygroup
mygroup:x:1010:
</code></pre></div></div>
<p>If a group with the given GID already exist, you will get the following error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd: GID '1010' already exists
</code></pre></div></div>
<p>When used with the -o (non-unique) option the groupadd command allows you to create a group with non-unique GID:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd -o -g 1010 mygroup
</code></pre></div></div>
<h3 id="creating-a-system-group">Creating a System Group</h3>
<p>There is no real technical difference between the system and regular (normal) groups. Usually, system groups are used for some special system operation purposes, like creating backups or doing system maintenance.</p>
<p>System groups GIDs are chosen from the range of system group UDs specified in the login.defs file, which is different than the range used for regular groups.</p>
<p>Use the <code class="language-plaintext highlighter-rouge">-r (--system)</code> option to create a system group. For example, to create a new system group named mysystemgroup you would run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd -r mysystemgroup
</code></pre></div></div>
<h3 id="overriding-the-default-values">Overriding the Default Values</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/login.defs
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">-K (--key)</code> option followed by KEY=VAL allows you to override the default values specified in the /etc/login.defs file.</p>
<p>Basically, all you can override are the maximum and minimum values of the normal and system group IDs for automatic GID selection when creating a new group.</p>
<p>Lets say you want to create a new group with GID in the range between 1200 and 1500. To do that, specify the min/max values as shown below:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd -K GID_MIN=1200 -K GID_MAX=1500 mygroup
</code></pre></div></div>
<h3 id="creating-a-system-group-with-password">Creating a System Group with Password</h3>
<p>Adding a password to a group has no practical use and may cause a security problem since more than one user will need to know the password.</p>
<p>The <code class="language-plaintext highlighter-rouge">-p (--password)</code> option followed by password allows you to set a password for the new group:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groupadd -p grouppassword mygroup
</code></pre></div></div>
</div>
<div class="d-print-none">
<footer class="article__footer"><meta itemprop="dateModified" content="2019-10-17T00:00:00+02:00">
<!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix">
<div class="previous">
<span>PRÉCÉDENT</span><a href="/2019/10/08/SSO-module-Nginx-'auth_request'.html">Guide et SSO avec le module Nginx 'auth_request'</a>
</div>
<div class="next">
<span>SUIVANT</span><a href="/2019/10/21/Annuaire-LDAP-xoyize.xyz-(exPC2).html">OpenLDAP installation et configuration annuaire xoyize.xyz</a>
</div>
</div>
</div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
$(function() {
var $this ,$scroll;
var $articleContent = $('.js-article-content');
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
$scroll = $(scroll);
$articleContent.find('.highlight').each(function() {
$this = $(this);
$this.attr('data-lang', $this.find('code').attr('data-lang'));
});
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
$this = $(this);
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
});
$articleContent.on('click', '.anchor', function() {
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
});
});
});
})();
</script>
</div>
<section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
<!-- end custom main bottom snippet -->
</div>
</div></div></div>
</div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $body = $('body'), $window = $(window);
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
var activeCount = 0;
function modal(options) {
var $root = this, visible, onChange, hideWhenWindowScroll = false;
var scrollTop;
function setOptions(options) {
var _options = options || {};
visible = _options.initialVisible === undefined ? false : show;
onChange = _options.onChange;
hideWhenWindowScroll = _options.hideWhenWindowScroll;
}
function init() {
setState(visible);
}
function setState(isShow) {
if (isShow === visible) {
return;
}
visible = isShow;
if (visible) {
activeCount++;
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
$root.addClass('modal--show');
$pageMain.scrollTop(scrollTop);
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
$window.on('keyup', handleKeyup);
} else {
activeCount > 0 && activeCount--;
$root.removeClass('modal--show');
$window.scrollTop(scrollTop);
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
$window.off('keyup', handleKeyup);
}
onChange && onChange(visible);
}
function show() {
setState(true);
}
function hide() {
setState(false);
}
function handleKeyup(e) {
// Char Code: 27 ESC
if (e.which === 27) {
hide();
}
}
setOptions(options);
init();
return {
show: show,
hide: hide,
$el: $root
};
}
$.fn.modal = modal;
});
})();
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal">
<script>
(function () {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
// search panel
var search = (window.search || (window.search = {}));
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
true : window.useDefaultSearchBox ;
var $searchModal = $('.js-page-search-modal');
var $searchToggle = $('.js-search-toggle');
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
var modalVisible = false;
search.searchModal = searchModal;
var $searchBox = null;
var $searchInput = null;
var $searchClear = null;
function getModalVisible() {
return modalVisible;
}
search.getModalVisible = getModalVisible;
function handleModalChange(visible) {
modalVisible = visible;
if (visible) {
search.onShow && search.onShow();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
} else {
search.onShow && search.onHide();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
setTimeout(function() {
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
search.clear && search.clear();
window.pageAsideAffix && window.pageAsideAffix.refresh();
}, 400);
}
}
$searchToggle.on('click', function() {
modalVisible ? searchModal.hide() : searchModal.show();
});
// Char Code: 83 S, 191 /
$(window).on('keyup', function(e) {
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
modalVisible || searchModal.show();
}
});
if (useDefaultSearchBox) {
$searchBox = $('.js-search-box');
$searchInput = $searchBox.children('input');
$searchClear = $searchBox.children('.js-icon-clear');
search.getSearchInput = function() {
return $searchInput.get(0);
};
search.getVal = function() {
return $searchInput.val();
};
search.setVal = function(val) {
$searchInput.val(val);
};
$searchInput.on('focus', function() {
$(this).addClass('focus');
});
$searchInput.on('blur', function() {
$(this).removeClass('focus');
});
$searchInput.on('input', window.throttle(function() {
var val = $(this).val();
if (val === '' || typeof val !== 'string') {
search.clear && search.clear();
} else {
$searchBox.addClass('not-empty');
search.onInputNotEmpty && search.onInputNotEmpty(val);
}
}, 400));
$searchClear.on('click', function() {
$searchInput.val(''); $searchBox.removeClass('not-empty');
search.clear && search.clear();
});
}
});
})();
</script><div class="search search--dark">
<div class="main">
<div class="search__header">Recherche</div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text">
<div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div>
</div>
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
Annuler</button>
</div>
<div id="results-container" class="search-result js-search-result"></div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
noResultsText: '<p>Aucun résultat!</p>',
json: '/search.json',
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a>&nbsp;(Création {create})</li>'
})
</script>
</div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script><!---->
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>